├── .angular-cli.json ├── .ebextensions ├── app.config └── nodecommand.config ├── .gitignore ├── LICENSE ├── README.md ├── app.js ├── aws ├── authrole-trust-policy.json ├── authrole.json ├── cognito-quickstart-app-overview.png ├── createResources.sh ├── meta │ ├── Cognito-Angular2-QuickStart.png │ └── Cognito-Angular2-QuickStart.xml ├── s3-bucket-policy.json ├── unauthrole-trust-policy.json ├── unauthrole.json ├── user-pool-policy.json └── user-pool-schema.json ├── bin └── www ├── package.json ├── routes └── index.js ├── src ├── app │ ├── app.component.ts │ ├── app.module.ts │ ├── app.routes.ts │ ├── index.ts │ ├── public │ │ ├── auth │ │ │ ├── confirm │ │ │ │ ├── confirmRegistration.component.ts │ │ │ │ └── confirmRegistration.html │ │ │ ├── forgot │ │ │ │ ├── forgotPassword.component.ts │ │ │ │ ├── forgotPassword.html │ │ │ │ └── forgotPasswordStep2.html │ │ │ ├── login │ │ │ │ ├── login.component.ts │ │ │ │ └── login.html │ │ │ ├── mfa │ │ │ │ ├── mfa.component.ts │ │ │ │ └── mfa.html │ │ │ ├── newpassword │ │ │ │ ├── newpassword.component.ts │ │ │ │ └── newpassword.html │ │ │ ├── register │ │ │ │ ├── registration.component.ts │ │ │ │ └── registration.html │ │ │ └── resend │ │ │ │ ├── resendCode.component.ts │ │ │ │ └── resendCode.html │ │ ├── home.component.ts │ │ ├── home.html │ │ └── landinghome.html │ ├── secure │ │ ├── jwttokens │ │ │ ├── jwt.component.ts │ │ │ └── jwt.html │ │ ├── landing │ │ │ ├── secureHome.css │ │ │ ├── secureHome.html │ │ │ └── securehome.component.ts │ │ ├── profile │ │ │ ├── myprofile.component.ts │ │ │ └── myprofile.html │ │ └── useractivity │ │ │ ├── useractivity.component.ts │ │ │ └── useractivity.html │ ├── service │ │ ├── aws.service.ts │ │ ├── cognito.service.ts │ │ ├── ddb.service.ts │ │ ├── s3.service.ts │ │ ├── user-login.service.ts │ │ ├── user-parameters.service.ts │ │ └── user-registration.service.ts │ ├── shared │ │ └── index.ts │ └── template │ │ └── app.html ├── assets │ ├── css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.min.css │ │ ├── font-awesome.min.css │ │ ├── login-form.css │ │ ├── sb-admin-2.min.css │ │ └── starter.css │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── img │ │ └── intro-bg.jpg │ └── ui-js │ │ ├── bootstrap.min.js │ │ ├── jquery.min.js │ │ ├── metisMenu.min.js │ │ └── sb-admin-2.min.js ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css ├── tsconfig.app.json ├── tsconfig.spec.json └── typings.d.ts └── tslint.json /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "version": "1.0.0-beta.14", 4 | "name": "aws-cognito-quickstart" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "test": "test.ts", 17 | "tsconfig": "tsconfig.app.json", 18 | "testTsconfig": "tsconfig.spec.json", 19 | "prefix": "app", 20 | "mobile": false, 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "addons": [], 33 | "packages": [], 34 | "e2e": { 35 | "protractor": { 36 | "config": "./protractor.conf.js" 37 | } 38 | }, 39 | "test": { 40 | "karma": { 41 | "config": "./karma.conf.js" 42 | } 43 | }, 44 | "defaults": { 45 | "styleExt": "css", 46 | "prefixInterfaces": false 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.ebextensions/app.config: -------------------------------------------------------------------------------- 1 | packages: 2 | yum: 3 | krb5-devel: [] -------------------------------------------------------------------------------- /.ebextensions/nodecommand.config: -------------------------------------------------------------------------------- 1 | option_settings: 2 | aws:elasticbeanstalk:container:nodejs: 3 | NodeCommand: "npm run startnode" 4 | ProxyServer: nginx 5 | GzipCompression: true 6 | aws:elasticbeanstalk:container:nodejs:staticfiles: 7 | /assets: /dist/assets -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /src/bower_components 10 | /public/bower_components 11 | package-lock.json 12 | 13 | # IDEs and editors 14 | /.idea 15 | 16 | # misc 17 | /.sass-cache 18 | /connect.lock 19 | /coverage/* 20 | /libpeerconnection.log 21 | npm-debug.log 22 | testem.log 23 | /typings 24 | 25 | # e2e 26 | /e2e/*.js 27 | /e2e/*.map 28 | 29 | #System Files 30 | .DS_Store 31 | Thumbs.db 32 | 33 | # Elastic Beanstalk Files 34 | .elasticbeanstalk/* 35 | !.elasticbeanstalk/*.cfg.yml 36 | !.elasticbeanstalk/*.global.yml 37 | 38 | # Build Artifacts 39 | upload.zip 40 | resetConfig.sh -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cognito Quickstart 2 | =================================================== 3 | #### Creator: Vladimir Budilov 4 | * [YouTube](https://www.youtube.com/channel/UCBl-ENwdTlUsLY05yGgXyxw) 5 | * [LinkedIn](https://www.linkedin.com/in/vbudilov/) 6 | * [Medium](https://medium.com/@budilov) 7 | 8 | # Note: This repo is deprecated. It was created before the [Amplify SDK](https://aws-amplify.github.io/docs/js/angular) was available which performs a lot of the plumbing for you. Please use the [Amplify SDK](https://aws-amplify.github.io/docs/js/angular) going forward. [Here's an example](https://github.com/vbudilov/reactjs-cognito-starter) of its use with ReactJS as well. 9 | 10 | ## What does this app do? 11 | ![QuickStart Angular2 Cognito App](/aws/meta/Cognito-Angular2-QuickStart.png?raw=true) 12 | 13 | ## Tech Stack 14 | ### Required Tools 15 | * [aws cli](http://docs.aws.amazon.com/cli/latest/userguide/installing.html) 16 | * [eb cli](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html) 17 | * [npm](https://www.npmjs.com/) 18 | * [angular-cli](https://github.com/angular/angular-cli) 19 | 20 | ### Frameworks 21 | * [AWS JavaScript SDK](http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-intro.html) 22 | * [Angular 2](https://angular.io/docs/ts/latest/quickstart.html) 23 | * [TypeScript](https://www.typescriptlang.org/docs/tutorial.html) 24 | * [Bootstrap](http://getbootstrap.com/) 25 | 26 | ## AWS Setup 27 | ##### Install the required tools (the installation script only runs on Linux and Mac) 28 | * Create an AWS account 29 | * Install [npm](https://www.npmjs.com/) 30 | * [Install or update your aws cli](http://docs.aws.amazon.com/cli/latest/userguide/installing.html) 31 | * [Install or update your eb cli](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html) 32 | * [Install angular-cli](https://github.com/angular/angular-cli) 33 | 34 | 35 | ## Getting the code and running it locally 36 | _This uses the pre-configured AWS resources hosted by AWS_ 37 | 38 | ``` 39 | # Clone it from github 40 | git clone --depth 1 git@github.com:awslabs/aws-cognito-angular2-quickstart.git 41 | ``` 42 | ``` 43 | # Install the NPM packages 44 | cd aws-cognito-angular2-quickstart 45 | npm install 46 | ``` 47 | ``` 48 | # Run the app in dev mode 49 | npm start 50 | ``` 51 | 52 | ## Creating AWS Resources 53 | This sample application can be deployed to either Elastic Beanstalk or S3. S3 will host this application as a static site 54 | while Elastic Beanstalk gives you the capability of adding backend operations to the application. 55 | 56 | * [What is Elastic Beanstalk](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/Welcome.html) 57 | * [What is S3](http://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html) 58 | 59 | **createResources.sh requires your [aws cli to be configured](http://docs.aws.amazon.com/cli/latest/userguide/controlling-output.html) for JSON output.** 60 | 61 | ``` 62 | # Install the AWS resources and deploy your application to either Elastic Beanstalk or S3 63 | cd aws 64 | ./createResources.sh 65 | ``` 66 | 67 | Running the above command will create the necessary AWS resources and build & deploy your code to AWS. 68 | It will prompt you to choose your deployment target (S3 or Elastic Beanstalk). Choosing 'S3' makes your deployment 69 | completely serverless, while choosing Elastic Beanstalk will create an EC2 instance that will host this NodeJS app. 70 | 71 | *Caution:* You might incur AWS charges after running the setup script 72 | 73 | ## After initially running the ```createResources.sh``` script, use the below commands to rebuild and redeploy 74 | 75 | ### _S3:_ Update, Build and Deploy 76 | ``` 77 | # Build the project and sync the output with the S3 bucket 78 | npm run build; cd dist; aws s3 sync . s3://[BUCKET_NAME]/ 79 | ``` 80 | ``` 81 | # Test your deployed application 82 | curl –I http://[BUCKET_NAME].s3-website-[REGION].amazonaws.com/ 83 | ``` 84 | __*NOTE: You might want to reshuffle some of the "package.json" dependencies and move the ones that belong to devDependencies 85 | for a leaner deployment bundle. At this point of time, AWS Beanstalk requires all of the dependencies, 86 | including the devDependencies to be under the dependencies section. But if you're not using Beanstalk then you can 87 | optimize as you wish.*__ 88 | 89 | *or* 90 | 91 | ### _Beanstalk:_ Update, Build and Deploy 92 | ``` 93 | # Commit your changes in order to deploy it to your environment 94 | git add . 95 | git commit 96 | eb deploy 97 | ``` 98 | ``` 99 | # View your deployed application in a browser 100 | eb open 101 | ``` 102 | 103 | ## Local Testing 104 | 105 | This section contains instructions on how to test the application locally (using mocked services instead of the real AWS services). 106 | 107 | ### LocalStack 108 | 109 | To test this application using [LocalStack](https://github.com/localstack/localstack), you can use the `awslocal` CLI (https://github.com/localstack/awscli-local). 110 | ``` 111 | pip install awscli-local 112 | ``` 113 | Simply parameterize the `./createResources.sh` installation script with `aws_cmd=awslocal`: 114 | ``` 115 | cd aws; aws_cmd=awslocal ./createResources.sh 116 | ``` 117 | Once the code is deployed to the local S3 server, the application is accessible via http://localhost:4572/cognitosample-localapp/index.html (Assuming "localapp" has been chosen as resource name in the previous step) 118 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var routes = require('./routes/index'); 9 | 10 | var app = express(); 11 | 12 | // view engine setup 13 | app.set('views', path.join(__dirname, 'dist')); 14 | app.set('view engine', 'ejs'); 15 | app.engine('html', require('ejs').renderFile); 16 | 17 | // uncomment after placing your favicon in /public 18 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 19 | app.use(logger('dev')); 20 | app.use(bodyParser.json()); 21 | app.use(bodyParser.urlencoded({ extended: false })); 22 | app.use(cookieParser()); 23 | app.use(express.static(path.join(__dirname, 'dist'))); 24 | 25 | app.use('/', routes); 26 | 27 | // catch 404 and forward to error handler 28 | app.use(function(req, res, next) { 29 | var err = new Error('Not Found'); 30 | err.status = 404; 31 | next(err); 32 | }); 33 | 34 | // error handlers 35 | 36 | // development error handler 37 | // will print stacktrace 38 | if (app.get('env') === 'development') { 39 | app.use(function(err, req, res, next) { 40 | res.status(err.status || 500); 41 | res.render('error', { 42 | message: err.message, 43 | error: err 44 | }); 45 | }); 46 | } 47 | 48 | // production error handler 49 | // no stacktraces leaked to user 50 | app.use(function(err, req, res, next) { 51 | res.status(err.status || 500); 52 | res.render('error', { 53 | message: err.message, 54 | error: {} 55 | }); 56 | }); 57 | 58 | 59 | module.exports = app; 60 | -------------------------------------------------------------------------------- /aws/authrole-trust-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Federated": "cognito-identity.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRoleWithWebIdentity", 10 | "Condition": { 11 | "StringEquals": { 12 | "cognito-identity.amazonaws.com:aud": "IDENTITY_POOL" 13 | }, 14 | "ForAnyValue:StringLike": { 15 | "cognito-identity.amazonaws.com:amr": "authenticated" 16 | } 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /aws/authrole.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "mobileanalytics:PutEvents", 8 | "cognito-sync:*", 9 | "cognito-identity:*" 10 | ], 11 | "Resource": [ 12 | "*" 13 | ] 14 | }, 15 | { 16 | "Effect": "Allow", 17 | "Action": [ 18 | "dynamodb:GetItem", 19 | "dynamodb:BatchGetItem", 20 | "dynamodb:Query", 21 | "dynamodb:PutItem", 22 | "dynamodb:UpdateItem", 23 | "dynamodb:DeleteItem" 24 | ], 25 | "Resource": [ 26 | "DDB_TABLE_ARN" 27 | ], 28 | "Condition": { 29 | "ForAllValues:StringEquals": { 30 | "dynamodb:LeadingKeys": [ 31 | "${cognito-identity.amazonaws.com:sub}" 32 | ] 33 | } 34 | } 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /aws/cognito-quickstart-app-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/aws/cognito-quickstart-app-overview.png -------------------------------------------------------------------------------- /aws/createResources.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | aws_cmd=${aws_cmd:-aws} 4 | 5 | # Bucket name must be all lowercase, and start/end with lowecase letter or number 6 | # $(echo...) code to work with versions of bash older than 4.0 7 | 8 | echo -n "Enter the name for your resources (must be all lowercase with no spaces) and press [ENTER]: " 9 | read ROOT_NAME 10 | 11 | BUCKET_NAME=cognitosample-$(echo "$ROOT_NAME" | tr '[:upper:]' '[:lower:]') 12 | TABLE_NAME=LoginTrail$ROOT_NAME 13 | 14 | ROLE_NAME_PREFIX=$ROOT_NAME 15 | POOL_NAME=$ROOT_NAME 16 | IDENTITY_POOL_NAME=$ROOT_NAME 17 | REGION=us-east-2 18 | EB_INSTANCE_TYPE=t2.small 19 | EB_PLATFORM=node.js 20 | CURR_DIR=$( cd $(dirname $0) ; pwd -P ) 21 | ROOT_DIR=$( cd $CURR_DIR; cd ..; pwd -P) 22 | NPM_DIR=$ROOT_DIR/node_modules/ 23 | 24 | DDB_TABLE_ARN="" 25 | IDENTITY_POOL_ID="" 26 | USER_POOL_ID="" 27 | USER_POOL_CLIENT_ID="" 28 | 29 | createCognitoResources() { 30 | # Create a Cognito Identity and Set roles 31 | $aws_cmd cognito-identity create-identity-pool --identity-pool-name $IDENTITY_POOL_NAME --allow-unauthenticated-identities --region $REGION| grep IdentityPoolId | awk '{print $2}' | xargs |sed -e 's/^"//' -e 's/"$//' -e 's/,$//' > /tmp/poolId 32 | IDENTITY_POOL_ID=$(cat /tmp/poolId) 33 | echo "Created an identity pool with id of " $IDENTITY_POOL_ID 34 | 35 | # Create an IAM role for unauthenticated users 36 | cat unauthrole-trust-policy.json | sed 's/IDENTITY_POOL/'$IDENTITY_POOL_ID'/' > /tmp/unauthrole-trust-policy.json 37 | $aws_cmd iam create-role --role-name $ROLE_NAME_PREFIX-unauthenticated-role --assume-role-policy-document file:///tmp/unauthrole-trust-policy.json > /tmp/iamUnauthRole 38 | if [ $? -eq 0 ] 39 | then 40 | echo "IAM unauthenticated role successfully created" 41 | else 42 | echo "Using the existing role ..." 43 | $aws_cmd iam get-role --role-name $ROLE_NAME_PREFIX-unauthenticated-role > /tmp/iamUnauthRole 44 | $aws_cmd iam update-assume-role-policy --role-name $ROLE_NAME_PREFIX-unauthenticated-role --policy-document file:///tmp/unauthrole-trust-policy.json 45 | fi 46 | $aws_cmd iam put-role-policy --role-name $ROLE_NAME_PREFIX-unauthenticated-role --policy-name CognitoPolicy --policy-document file://unauthrole.json 47 | 48 | # Create an IAM role for authenticated users 49 | cat authrole-trust-policy.json | sed 's/IDENTITY_POOL/'$IDENTITY_POOL_ID'/' > /tmp/authrole-trust-policy.json 50 | $aws_cmd iam create-role --role-name $ROLE_NAME_PREFIX-authenticated-role --assume-role-policy-document file:///tmp/authrole-trust-policy.json > /tmp/iamAuthRole 51 | if [ $? -eq 0 ] 52 | then 53 | echo "IAM authenticated role successfully created" 54 | else 55 | echo "Using the existing role ..." 56 | $aws_cmd iam get-role --role-name $ROLE_NAME_PREFIX-authenticated-role > /tmp/iamAuthRole 57 | $aws_cmd iam update-assume-role-policy --role-name $ROLE_NAME_PREFIX-authenticated-role --policy-document file:///tmp/authrole-trust-policy.json 58 | fi 59 | cat authrole.json | sed 's~DDB_TABLE_ARN~'$DDB_TABLE_ARN'~' > /tmp/authrole.json 60 | $aws_cmd iam put-role-policy --role-name $ROLE_NAME_PREFIX-authenticated-role --policy-name CognitoPolicy --policy-document file:///tmp/authrole.json 61 | 62 | # Create the user pool 63 | $aws_cmd cognito-idp create-user-pool --pool-name $POOL_NAME --auto-verified-attributes email --policies file://user-pool-policy.json --region $REGION > /tmp/$POOL_NAME-create-user-pool 64 | USER_POOL_ID=$(grep -E '"Id":' /tmp/$POOL_NAME-create-user-pool | awk -F'"' '{print $4}') 65 | echo "Created user pool with an id of " $USER_POOL_ID 66 | 67 | # Create the user pool client 68 | $aws_cmd cognito-idp create-user-pool-client --user-pool-id $USER_POOL_ID --no-generate-secret --client-name webapp --region $REGION > /tmp/$POOL_NAME-create-user-pool-client 69 | USER_POOL_CLIENT_ID=$(grep -E '"ClientId":' /tmp/$POOL_NAME-create-user-pool-client | awk -F'"' '{print $4}') 70 | echo "Created user pool client with id of " $USER_POOL_CLIENT_ID 71 | 72 | # Add the user pool and user pool client id to the identity pool 73 | $aws_cmd cognito-identity update-identity-pool --allow-unauthenticated-identities --identity-pool-id $IDENTITY_POOL_ID --identity-pool-name $IDENTITY_POOL_NAME \ 74 | --cognito-identity-providers ProviderName=cognito-idp.$REGION.amazonaws.com/$USER_POOL_ID,ClientId=$USER_POOL_CLIENT_ID --region $REGION \ 75 | > /tmp/$IDENTITY_POOL_ID-add-user-pool 76 | 77 | # Update cognito identity with the roles 78 | UNAUTH_ROLE_ARN=$(perl -nle 'print $& if m{"Arn":\s*"\K([^"]*)}' /tmp/iamUnauthRole | awk -F'"' '{print $1}') 79 | AUTH_ROLE_ARN=$(perl -nle 'print $& if m{"Arn":\s*"\K([^"]*)}' /tmp/iamAuthRole | awk -F'"' '{print $1}') 80 | $aws_cmd cognito-identity set-identity-pool-roles --identity-pool-id $IDENTITY_POOL_ID --roles authenticated=$AUTH_ROLE_ARN,unauthenticated=$UNAUTH_ROLE_ARN --region $REGION 81 | } 82 | 83 | createDDBTable() { 84 | # Create DDB Table 85 | $aws_cmd dynamodb create-table \ 86 | --table-name $TABLE_NAME \ 87 | --attribute-definitions \ 88 | AttributeName=userId,AttributeType=S \ 89 | AttributeName=activityDate,AttributeType=S \ 90 | --key-schema AttributeName=userId,KeyType=HASH AttributeName=activityDate,KeyType=RANGE \ 91 | --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \ 92 | --region $REGION \ 93 | > /tmp/dynamoTable 94 | 95 | if [ $? -eq 0 ] 96 | then 97 | echo "DynamoDB table successfully created" 98 | else 99 | echo "Using the existing table ..." 100 | $aws_cmd dynamodb describe-table --table-name $TABLE_NAME > /tmp/dynamoTable 101 | fi 102 | 103 | DDB_TABLE_ARN=$(perl -nle 'print $& if m{"TableArn":\s*"\K([^"]*)}' /tmp/dynamoTable | awk -F'"' '{print $1}') 104 | } 105 | 106 | createEBResources() { 107 | verifyEBCLI 108 | 109 | # Commit changes made 110 | cd $ROOT_DIR 111 | npm run-script build 112 | 113 | # Create Elastic Beanstalk application 114 | eb init $ROOT_NAME --region $REGION --platform $EB_PLATFORM 115 | sleep 1 116 | 117 | zip -r upload.zip . -x node_modules/\* *.git* *.idea* *.DS_Store* 118 | cat <> $ROOT_DIR/.elasticbeanstalk/config.yml 119 | deploy: 120 | artifact: upload.zip 121 | EOT 122 | 123 | sleep 1 124 | 125 | # Create Elastic Beanstalk environment 126 | eb create $ROOT_NAME -d --region $REGION --platform $EB_PLATFORM --instance_type $EB_INSTANCE_TYPE 127 | 128 | cd $CURR_DIR 129 | } 130 | 131 | createS3Bucket() { 132 | # Create the bucket 133 | $aws_cmd s3 mb s3://$BUCKET_NAME/ --region $REGION 2>/tmp/s3-mb-status 134 | status=$? 135 | 136 | if [ $status -eq 0 ] 137 | then 138 | echo "S3 bucket successfully created. Uploading files to S3." 139 | uploadS3Bucket 140 | else 141 | if grep "BucketAlreadyOwnedByYou" /tmp/s3-mb-status > /dev/null 142 | then 143 | echo "Using the existing S3 bucket ..." 144 | uploadS3Bucket 145 | else 146 | echo -n "The requested S3 bucket name is not available. Please enter a different name and try again : " 147 | read newName 148 | BUCKET_NAME=cognitosample-$(echo "$newName" | tr '[:upper:]' '[:lower:]') 149 | echo "Attempting to create bucket named $BUCKET_NAME" 150 | createS3Bucket 151 | fi 152 | fi 153 | } 154 | 155 | uploadS3Bucket() { 156 | # Add the ‘website’ configuration and bucket policy 157 | $aws_cmd s3 website s3://$BUCKET_NAME/ --index-document index.html --error-document index.html --region $REGION 158 | cat s3-bucket-policy.json | sed 's/BUCKET_NAME/'$BUCKET_NAME'/' > /tmp/s3-bucket-policy.json 159 | $aws_cmd s3api put-bucket-policy --bucket $BUCKET_NAME --policy file:///tmp/s3-bucket-policy.json --region $REGION 160 | #Build the project and sync it up to the bucket 161 | if [ ! -d "$NPM_DIR" ]; then 162 | npm install 163 | fi 164 | cd .. 165 | echo "Building the project" 166 | ng build $( if [ "$aws_cmd" == "awslocal" ]; then echo "--base-href /$BUCKET_NAME/"; fi ) 167 | cd - 168 | echo "Syncing files to the S3 bucket from " $ROOT_DIR/dist/ 169 | $aws_cmd s3 sync $ROOT_DIR/dist/ s3://$BUCKET_NAME/ --region $REGION 170 | } 171 | 172 | printConfig() { 173 | echo "Region: " $REGION 174 | echo "DynamoDB: " $TABLE_NAME 175 | echo "Bucket name: " $BUCKET_NAME 176 | echo "Identity Pool name: " $IDENTITY_POOL_NAME 177 | echo "Identity Pool id: " $IDENTITY_POOL_ID 178 | echo "Finished AWS resource creation. Status: SUCCESS" 179 | } 180 | 181 | provisionGlobalResources() { 182 | createDDBTable 183 | createCognitoResources 184 | writeConfigFiles 185 | } 186 | 187 | verifyEBCLI() { 188 | if command -v eb >/dev/null; then 189 | echo "Creating Elastic Beanstalk environment. This can take more than 10 min ..." 190 | else 191 | echo "Please install the Elastic Beanstalk Command Line Interface first" 192 | exit 1; 193 | fi 194 | } 195 | 196 | writeConfigFiles() { 197 | ( 198 | cat < $ROOT_DIR/src/environments/environment.ts 223 | 224 | ( 225 | cat < $ROOT_DIR/src/environments/environment.prod.ts 250 | 251 | } 252 | 253 | 254 | 255 | if [[ $ROOT_NAME =~ [[:upper:]]|[[:space:]] || -z "$ROOT_NAME" ]]; then 256 | echo "Invalid format" 257 | exit 1 258 | else 259 | echo "All AWS resources will be created with [$ROOT_NAME] as part of their name" 260 | 261 | PS3='Where would you like to deploy your application? ' 262 | options=("Elastic Beanstalk" "S3" "Quit") 263 | select opt in "${options[@]}" 264 | do 265 | case $opt in 266 | "Elastic Beanstalk") 267 | provisionGlobalResources 268 | createEBResources 269 | printConfig 270 | break 271 | ;; 272 | "S3") 273 | provisionGlobalResources 274 | createS3Bucket 275 | printConfig 276 | break 277 | ;; 278 | "Quit") 279 | exit 1 280 | ;; 281 | *) 282 | echo "Invalid option" 283 | exit 1 284 | ;; 285 | esac 286 | done 287 | fi 288 | -------------------------------------------------------------------------------- /aws/meta/Cognito-Angular2-QuickStart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/aws/meta/Cognito-Angular2-QuickStart.png -------------------------------------------------------------------------------- /aws/meta/Cognito-Angular2-QuickStart.xml: -------------------------------------------------------------------------------- 1 | 5Vpdb+MoFP01kWYfJrKN7SSPTdLpVtqVKnVXnXmqiE0ctthYQD48v37Bxp+4nc7EybRpXwo3FxvOOfdyIRmBRXy4YTDd/E1DREaOFR5GYDlyHNvxLflPWbLCMrH9whAxHGqn2nCPvyNt1OOiLQ4RbzkKSonAadsY0CRBgWjZIGN033ZbU9J+awojZBjuA0hM6wMOxaawTj2rtv+JcLQp32xb+pMVDJ4iRreJft/IAev8r/g4huWztD/fwJDuGyZwPQILRqkoWvFhgYjCtoStGPflmU+reTOUiNcMmOlpiKxcOgolErpLmdjQiCaQXNfWeb48pB5gyd5GxEQ2bdlEByy+KvN45uvut7zr6d4dYjhGAjE9Vk6SZV+bnYa/6nYH/IeEyLRc4FZQaarn+BelqZ6JCYNGhtMtC/RKHS0syCKkvUBhUhg0hmnobhCVc2GZdGCIQIF3bbVALbqo8tNDrxiDWcMhpTgRvPHkO2WQDjp+QBkGOnocG7RJ/IG/7fpNf9koZlD2GkupTbkwnlHV5EQqAS2VVN03L5PJm5CJPfNatANrWNqrHDUw7dbkndLuvQ3aQZt2z+2k+G528OyX/I+XiXMamXgNldjvRSKl23AaafD0Ig3gRDT89FZeg18xdzwTHTx/iRrvTEzod+8g2aKyCuwwE0K+6YNdloOpcokPkSqsx3DPnXFCk88csR0O0CNPUYDXOBjLEEcsUWubc8HoE1pQQhW20hu9JOAdYgIdXtRmlWg6ZcVM9/d1STzRpk2jGtbVx3FqHhhDLiiTRfsjTMJHeWgQEpVHeWiRtLNszMEJUQRuB0XbRNGbmShOnONRdA0U74GBo1yHaCPIEMff4Sp3UODqHUl6e/ORt5QWFbC8iF01ABIcJbJN0Fo9SoGD5WHqSpuFCuY5T2GAk+ifPLI/uwOh67fR7ZEo6JFoWdocA643sERDKOAKcjQOswTGNFydUpTdmsCank2UvoHbMl/wcn5h0uwEvtejzemJtDkZWJsxXWEid59iF+LjgEYJzvfscym02mnOoNCpgd5Cr9ex/pUYyH+3oVwaFhjJQt2HsRJRsuJpvnafKKWFeCebkWp++iYrk3rsHaXkj9JNzqXheWER4LQjALiOwaHt9oQAGCAEym22waI9lv25uh1Er2Atp5tjgT4CVY7VqVImE4OqvlpvEKbMgtlRTF1txUZFWQAVB5eF9qyd3DwzuVVXykPvDbZZFQIF9w1SlwZ1prtdXhbo1fGlzEY9+3FVnA8Ouln1uAr0B5YnGIvQSJ1yk/Kxl4N6p0DvqzRPhno13cupg8DUPVsd1HN+rNPDFxQiJjNz+IqttFktWZ90L/tQpZDdptH1TRpPVgoNflQNaJxuRXGbkiCxp+xJIjZGgfNcJKwxIb3BYUDYA/SzqLp2ex+1vTMGh5nRrxcmrr9btcfhC9qqtctFN/DtE+0QuRuYV4C3a9kPUUpo9qq0k+cpdeP1LvLLUUw5ficSykf84LJhiPQCzG3iZ5nacomIKvkf7tURDcGEC0iePgJzoJPDyi/7WztD3x3mL1Anu/VPS4qv+urf74Dr/wE= -------------------------------------------------------------------------------- /aws/s3-bucket-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version":"2012-10-17", 3 | "Statement":[{ 4 | "Sid":"PublicReadForGetBucketObjects", 5 | "Effect":"Allow", 6 | "Principal": "*", 7 | "Action":["s3:GetObject"], 8 | "Resource":["arn:aws:s3:::BUCKET_NAME/*" 9 | ] 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /aws/unauthrole-trust-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Principal": { 7 | "Federated": "cognito-identity.amazonaws.com" 8 | }, 9 | "Action": "sts:AssumeRoleWithWebIdentity", 10 | "Condition": { 11 | "StringEquals": { 12 | "cognito-identity.amazonaws.com:aud": "IDENTITY_POOL" 13 | }, 14 | "ForAnyValue:StringLike": { 15 | "cognito-identity.amazonaws.com:amr": "unauthenticated" 16 | } 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /aws/unauthrole.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": [ 7 | "mobileanalytics:PutEvents", 8 | "cognito-sync:*" 9 | ], 10 | "Resource": [ 11 | "*" 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /aws/user-pool-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "PasswordPolicy": { 3 | "MinimumLength": 8, 4 | "RequireUppercase": true, 5 | "RequireLowercase": true, 6 | "RequireNumbers": true, 7 | "RequireSymbols": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /aws/user-pool-schema.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "email", 4 | "AttributeDataType": "String", 5 | "DeveloperOnlyAttribute": false, 6 | "Mutable": false, 7 | "Required": true, 8 | "StringAttributeConstraints": { 9 | "MinLength": "0", 10 | "MaxLength": "2048" 11 | } 12 | } 13 | ] -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('CognitoDemo:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-cognito-angular-quickstart", 3 | "version": "1.0.0", 4 | "author": "Vladimir Budilov", 5 | "homepage": "http://cognito.budilov.com", 6 | "contributors": [ 7 | { 8 | "name": "Vladimir Budilov", 9 | "url": "http://budilov.com" 10 | } 11 | ], 12 | "description": "A single-page web app, based on angular4, utilizing Amazon Cognito, S3, and DynamoDB (serverless architecture)", 13 | "angular-cli": {}, 14 | "scripts": { 15 | "start": "ng serve --port 3333", 16 | "startnode": "node ./bin/www", 17 | "lint": "tslint \"src/**/*.ts\"", 18 | "test": "ng test", 19 | "pree2e": "webdriver-manager update", 20 | "e2e": "protractor", 21 | "build": "npm install && ng build --prod --aot=false" 22 | }, 23 | "private": true, 24 | "dependencies": { 25 | "@angular/animations": "5.2.2", 26 | "@angular/cli": "1.6.6", 27 | "@angular/common": "5.2.2", 28 | "@angular/compiler": "5.2.2", 29 | "@angular/compiler-cli": "5.2.2", 30 | "@angular/core": "5.2.2", 31 | "@angular/forms": "5.2.2", 32 | "@angular/http": "5.2.2", 33 | "@angular/platform-browser": "5.2.2", 34 | "@angular/platform-browser-dynamic": "5.2.2", 35 | "@angular/platform-server": "5.2.2", 36 | "@angular/router": "5.2.2", 37 | "@types/jasmine": "2.2.30", 38 | "@types/node": "^8.5.2", 39 | "@types/selenium-webdriver": "2.44.26", 40 | "amazon-cognito-identity-js": "1.29.0", 41 | "aws-sdk": "2.67.0", 42 | "body-parser": "~1.15.1", 43 | "codelyzer": "4.0.1", 44 | "cookie-parser": "~1.4.3", 45 | "core-js": "2.4.1", 46 | "debug": "~2.2.0", 47 | "ejs": "^2.5.2", 48 | "enhanced-resolve": "^3.3.0", 49 | "express": "~4.13.4", 50 | "extract-text-webpack-plugin": "2.1.0", 51 | "jasmine-core": "2.4.1", 52 | "jasmine-spec-reporter": "2.5.0", 53 | "karma": "1.2.0", 54 | "karma-chrome-launcher": "2.0.0", 55 | "karma-cli": "1.0.1", 56 | "karma-jasmine": "1.0.2", 57 | "karma-remap-istanbul": "0.6.0", 58 | "morgan": "~1.7.0", 59 | "protractor": "5.1.1", 60 | "rxjs": "5.5.4", 61 | "serve-favicon": "~2.3.0", 62 | "ts-helpers": "1.1.1", 63 | "ts-node": "3.2.0", 64 | "tslint": "5.7.0", 65 | "typescript": "2.4.2", 66 | "webpack": "2.2.1", 67 | "webpack-dev-middleware": "1.10.1", 68 | "webpack-dev-server": "2.4.2", 69 | "webpack-md5-hash": "0.0.5", 70 | "webpack-merge": "4.1.0", 71 | "zone.js": "0.8.20" 72 | }, 73 | "devDependencies": {} 74 | } 75 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var path = require('path'); 4 | 5 | /* GET home page. */ 6 | router.get('*', function(req, res, next) { 7 | res.render('index.html'); 8 | }); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Vladimir Budilov 3 | * 4 | * This is the entry-way into the routing logic. This is the first component that's called when the app 5 | * loads. 6 | * 7 | */ 8 | import {Component, OnInit} from "@angular/core"; 9 | import {AwsUtil} from "./service/aws.service"; 10 | import {UserLoginService} from "./service/user-login.service"; 11 | import {CognitoUtil, LoggedInCallback} from "./service/cognito.service"; 12 | 13 | @Component({ 14 | selector: 'app-root', 15 | templateUrl: 'template/app.html' 16 | }) 17 | export class AppComponent implements OnInit, LoggedInCallback { 18 | 19 | constructor(public awsUtil: AwsUtil, public userService: UserLoginService, public cognito: CognitoUtil) { 20 | console.log("AppComponent: constructor"); 21 | } 22 | 23 | ngOnInit() { 24 | console.log("AppComponent: Checking if the user is already authenticated"); 25 | this.userService.isAuthenticated(this); 26 | } 27 | 28 | isLoggedIn(message: string, isLoggedIn: boolean) { 29 | console.log("AppComponent: the user is authenticated: " + isLoggedIn); 30 | let mythis = this; 31 | this.cognito.getIdToken({ 32 | callback() { 33 | 34 | }, 35 | callbackWithParam(token: any) { 36 | // Include the passed-in callback here as well so that it's executed downstream 37 | console.log("AppComponent: calling initAwsService in callback") 38 | mythis.awsUtil.initAwsService(null, isLoggedIn, token); 39 | } 40 | }); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from "@angular/platform-browser"; 2 | import {NgModule} from "@angular/core"; 3 | import {FormsModule} from "@angular/forms"; 4 | import {HttpModule} from "@angular/http"; 5 | import {AppComponent} from "./app.component"; 6 | import {UserRegistrationService} from "./service/user-registration.service"; 7 | import {UserParametersService} from "./service/user-parameters.service"; 8 | import {UserLoginService} from "./service/user-login.service"; 9 | import {CognitoUtil} from "./service/cognito.service"; 10 | import {routing} from "./app.routes"; 11 | import {AboutComponent, HomeComponent, HomeLandingComponent} from "./public/home.component"; 12 | import {AwsUtil} from "./service/aws.service"; 13 | import {UseractivityComponent} from "./secure/useractivity/useractivity.component"; 14 | import {MyProfileComponent} from "./secure/profile/myprofile.component"; 15 | import {SecureHomeComponent} from "./secure/landing/securehome.component"; 16 | import {JwtComponent} from "./secure/jwttokens/jwt.component"; 17 | import {DynamoDBService} from "./service/ddb.service"; 18 | import {LoginComponent} from "./public/auth/login/login.component"; 19 | import {RegisterComponent} from "./public/auth/register/registration.component"; 20 | import {ForgotPassword2Component, ForgotPasswordStep1Component} from "./public/auth/forgot/forgotPassword.component"; 21 | import {LogoutComponent, RegistrationConfirmationComponent} from "./public/auth/confirm/confirmRegistration.component"; 22 | import {ResendCodeComponent} from "./public/auth/resend/resendCode.component"; 23 | import {NewPasswordComponent} from "./public/auth/newpassword/newpassword.component"; 24 | import { MFAComponent } from './public/auth/mfa/mfa.component'; 25 | 26 | 27 | @NgModule({ 28 | declarations: [ 29 | NewPasswordComponent, 30 | LoginComponent, 31 | LogoutComponent, 32 | RegistrationConfirmationComponent, 33 | ResendCodeComponent, 34 | ForgotPasswordStep1Component, 35 | ForgotPassword2Component, 36 | RegisterComponent, 37 | MFAComponent, 38 | AboutComponent, 39 | HomeLandingComponent, 40 | HomeComponent, 41 | UseractivityComponent, 42 | MyProfileComponent, 43 | SecureHomeComponent, 44 | JwtComponent, 45 | AppComponent 46 | ], 47 | imports: [ 48 | BrowserModule, 49 | FormsModule, 50 | HttpModule, 51 | routing 52 | ], 53 | providers: [ 54 | CognitoUtil, 55 | AwsUtil, 56 | DynamoDBService, 57 | UserRegistrationService, 58 | UserLoginService, 59 | UserParametersService], 60 | bootstrap: [AppComponent] 61 | }) 62 | export class AppModule { 63 | } 64 | -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import {RouterModule, Routes} from "@angular/router"; 2 | import {ModuleWithProviders} from "@angular/core"; 3 | import {AboutComponent, HomeComponent, HomeLandingComponent} from "./public/home.component"; 4 | import {SecureHomeComponent} from "./secure/landing/securehome.component"; 5 | import {MyProfileComponent} from "./secure/profile/myprofile.component"; 6 | import {JwtComponent} from "./secure/jwttokens/jwt.component"; 7 | import {UseractivityComponent} from "./secure/useractivity/useractivity.component"; 8 | import {LoginComponent} from "./public/auth/login/login.component"; 9 | import {RegisterComponent} from "./public/auth/register/registration.component"; 10 | import {ForgotPassword2Component, ForgotPasswordStep1Component} from "./public/auth/forgot/forgotPassword.component"; 11 | import {LogoutComponent, RegistrationConfirmationComponent} from "./public/auth/confirm/confirmRegistration.component"; 12 | import {ResendCodeComponent} from "./public/auth/resend/resendCode.component"; 13 | import {NewPasswordComponent} from "./public/auth/newpassword/newpassword.component"; 14 | 15 | const homeRoutes: Routes = [ 16 | { 17 | path: '', 18 | redirectTo: '/home', 19 | pathMatch: 'full' 20 | }, 21 | { 22 | path: 'home', 23 | component: HomeComponent, 24 | children: [ 25 | {path: 'about', component: AboutComponent}, 26 | {path: 'login', component: LoginComponent}, 27 | {path: 'register', component: RegisterComponent}, 28 | {path: 'confirmRegistration/:username', component: RegistrationConfirmationComponent}, 29 | {path: 'resendCode', component: ResendCodeComponent}, 30 | {path: 'forgotPassword/:email', component: ForgotPassword2Component}, 31 | {path: 'forgotPassword', component: ForgotPasswordStep1Component}, 32 | {path: 'newPassword', component: NewPasswordComponent}, 33 | {path: '', component: HomeLandingComponent} 34 | ] 35 | }, 36 | ]; 37 | 38 | const secureHomeRoutes: Routes = [ 39 | { 40 | 41 | path: '', 42 | redirectTo: '/securehome', 43 | pathMatch: 'full' 44 | }, 45 | { 46 | path: 'securehome', component: SecureHomeComponent, children: [ 47 | {path: 'logout', component: LogoutComponent}, 48 | {path: 'jwttokens', component: JwtComponent}, 49 | {path: 'myprofile', component: MyProfileComponent}, 50 | {path: 'useractivity', component: UseractivityComponent}, 51 | {path: '', component: MyProfileComponent}] 52 | } 53 | ]; 54 | 55 | const routes: Routes = [ 56 | { 57 | path: '', 58 | children: [ 59 | ...homeRoutes, 60 | ...secureHomeRoutes, 61 | { 62 | path: '', 63 | component: HomeComponent 64 | } 65 | ] 66 | }, 67 | 68 | 69 | ]; 70 | 71 | export const appRoutingProviders: any[] = []; 72 | 73 | export const routing: ModuleWithProviders = RouterModule.forRoot(routes); 74 | -------------------------------------------------------------------------------- /src/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app.component'; 2 | export * from './app.module'; 3 | -------------------------------------------------------------------------------- /src/app/public/auth/confirm/confirmRegistration.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnDestroy, OnInit} from "@angular/core"; 2 | import {ActivatedRoute, Router} from "@angular/router"; 3 | import {UserRegistrationService} from "../../../service/user-registration.service"; 4 | import {UserLoginService} from "../../../service/user-login.service"; 5 | import {LoggedInCallback} from "../../../service/cognito.service"; 6 | 7 | @Component({ 8 | selector: 'awscognito-angular2-app', 9 | template: '' 10 | }) 11 | export class LogoutComponent implements LoggedInCallback { 12 | 13 | constructor(public router: Router, 14 | public userService: UserLoginService) { 15 | this.userService.isAuthenticated(this) 16 | } 17 | 18 | isLoggedIn(message: string, isLoggedIn: boolean) { 19 | if (isLoggedIn) { 20 | this.userService.logout(); 21 | this.router.navigate(['/home']); 22 | } 23 | 24 | this.router.navigate(['/home']); 25 | } 26 | } 27 | 28 | @Component({ 29 | selector: 'awscognito-angular2-app', 30 | templateUrl: './confirmRegistration.html' 31 | }) 32 | export class RegistrationConfirmationComponent implements OnInit, OnDestroy { 33 | confirmationCode: string; 34 | email: string; 35 | errorMessage: string; 36 | private sub: any; 37 | 38 | constructor(public regService: UserRegistrationService, public router: Router, public route: ActivatedRoute) { 39 | } 40 | 41 | ngOnInit() { 42 | this.sub = this.route.params.subscribe(params => { 43 | this.email = params['username']; 44 | 45 | }); 46 | 47 | this.errorMessage = null; 48 | } 49 | 50 | ngOnDestroy() { 51 | this.sub.unsubscribe(); 52 | } 53 | 54 | onConfirmRegistration() { 55 | this.errorMessage = null; 56 | this.regService.confirmRegistration(this.email, this.confirmationCode, this); 57 | } 58 | 59 | cognitoCallback(message: string, result: any) { 60 | if (message != null) { //error 61 | this.errorMessage = message; 62 | console.log("message: " + this.errorMessage); 63 | } else { //success 64 | //move to the next step 65 | console.log("Moving to securehome"); 66 | // this.configs.curUser = result.user; 67 | this.router.navigate(['/securehome']); 68 | } 69 | } 70 | } 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/app/public/auth/confirm/confirmRegistration.html: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/app/public/auth/forgot/forgotPassword.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnDestroy, OnInit} from "@angular/core"; 2 | import {ActivatedRoute, Router} from "@angular/router"; 3 | import {UserLoginService} from "../../../service/user-login.service"; 4 | import {CognitoCallback} from "../../../service/cognito.service"; 5 | 6 | @Component({ 7 | selector: 'awscognito-angular2-app', 8 | templateUrl: './forgotPassword.html' 9 | }) 10 | export class ForgotPasswordStep1Component implements CognitoCallback { 11 | email: string; 12 | errorMessage: string; 13 | 14 | constructor(public router: Router, 15 | public userService: UserLoginService) { 16 | this.errorMessage = null; 17 | } 18 | 19 | onNext() { 20 | this.errorMessage = null; 21 | this.userService.forgotPassword(this.email, this); 22 | } 23 | 24 | cognitoCallback(message: string, result: any) { 25 | if (message == null && result == null) { //error 26 | this.router.navigate(['/home/forgotPassword', this.email]); 27 | } else { //success 28 | this.errorMessage = message; 29 | } 30 | } 31 | } 32 | 33 | 34 | @Component({ 35 | selector: 'awscognito-angular2-app', 36 | templateUrl: './forgotPasswordStep2.html' 37 | }) 38 | export class ForgotPassword2Component implements CognitoCallback, OnInit, OnDestroy { 39 | 40 | verificationCode: string; 41 | email: string; 42 | password: string; 43 | errorMessage: string; 44 | private sub: any; 45 | 46 | constructor(public router: Router, public route: ActivatedRoute, 47 | public userService: UserLoginService) { 48 | console.log("email from the url: " + this.email); 49 | } 50 | 51 | ngOnInit() { 52 | this.sub = this.route.params.subscribe(params => { 53 | this.email = params['email']; 54 | 55 | }); 56 | this.errorMessage = null; 57 | } 58 | 59 | ngOnDestroy() { 60 | this.sub.unsubscribe(); 61 | } 62 | 63 | onNext() { 64 | this.errorMessage = null; 65 | this.userService.confirmNewPassword(this.email, this.verificationCode, this.password, this); 66 | } 67 | 68 | cognitoCallback(message: string) { 69 | if (message != null) { //error 70 | this.errorMessage = message; 71 | console.log("result: " + this.errorMessage); 72 | } else { //success 73 | this.router.navigate(['/home/login']); 74 | } 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /src/app/public/auth/forgot/forgotPassword.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/app/public/auth/forgot/forgotPasswordStep2.html: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /src/app/public/auth/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | import { Router } from "@angular/router"; 3 | import { UserLoginService } from "../../../service/user-login.service"; 4 | import { ChallengeParameters, CognitoCallback, LoggedInCallback } from "../../../service/cognito.service"; 5 | import { DynamoDBService } from "../../../service/ddb.service"; 6 | 7 | @Component({ 8 | selector: 'awscognito-angular2-app', 9 | templateUrl: './login.html' 10 | }) 11 | export class LoginComponent implements CognitoCallback, LoggedInCallback, OnInit { 12 | email: string; 13 | password: string; 14 | errorMessage: string; 15 | mfaStep = false; 16 | mfaData = { 17 | destination: '', 18 | callback: null 19 | }; 20 | 21 | constructor(public router: Router, 22 | public ddb: DynamoDBService, 23 | public userService: UserLoginService) { 24 | console.log("LoginComponent constructor"); 25 | } 26 | 27 | ngOnInit() { 28 | this.errorMessage = null; 29 | console.log("Checking if the user is already authenticated. If so, then redirect to the secure site"); 30 | this.userService.isAuthenticated(this); 31 | } 32 | 33 | onLogin() { 34 | if (this.email == null || this.password == null) { 35 | this.errorMessage = "All fields are required"; 36 | return; 37 | } 38 | this.errorMessage = null; 39 | this.userService.authenticate(this.email, this.password, this); 40 | } 41 | 42 | cognitoCallback(message: string, result: any) { 43 | if (message != null) { //error 44 | this.errorMessage = message; 45 | console.log("result: " + this.errorMessage); 46 | if (this.errorMessage === 'User is not confirmed.') { 47 | console.log("redirecting"); 48 | this.router.navigate(['/home/confirmRegistration', this.email]); 49 | } else if (this.errorMessage === 'User needs to set password.') { 50 | console.log("redirecting to set new password"); 51 | this.router.navigate(['/home/newPassword']); 52 | } 53 | } else { //success 54 | this.ddb.writeLogEntry("login"); 55 | this.router.navigate(['/securehome']); 56 | } 57 | } 58 | 59 | handleMFAStep(challengeName: string, challengeParameters: ChallengeParameters, callback: (confirmationCode: string) => any): void { 60 | this.mfaStep = true; 61 | this.mfaData.destination = challengeParameters.CODE_DELIVERY_DESTINATION; 62 | this.mfaData.callback = (code: string) => { 63 | if (code == null || code.length === 0) { 64 | this.errorMessage = "Code is required"; 65 | return; 66 | } 67 | this.errorMessage = null; 68 | callback(code); 69 | }; 70 | } 71 | 72 | isLoggedIn(message: string, isLoggedIn: boolean) { 73 | if (isLoggedIn) { 74 | this.router.navigate(['/securehome']); 75 | } 76 | } 77 | 78 | cancelMFA(): boolean { 79 | this.mfaStep = false; 80 | return false; //necessary to prevent href navigation 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/app/public/auth/login/login.html: -------------------------------------------------------------------------------- 1 | 42 | 43 | -------------------------------------------------------------------------------- /src/app/public/auth/mfa/mfa.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'awscognito-mfa', 5 | templateUrl: './mfa.html' 6 | }) 7 | export class MFAComponent { 8 | @Input() destination: string; 9 | @Input() onSubmit: (code: string) => void; 10 | 11 | constructor() { 12 | console.log("MFAComponent constructor"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/app/public/auth/mfa/mfa.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | Authentication code has been sent to: {{destination}} 4 |
5 |
6 | 8 |
9 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /src/app/public/auth/newpassword/newpassword.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {Router} from "@angular/router"; 3 | import {UserRegistrationService} from "../../../service/user-registration.service"; 4 | import {UserLoginService} from "../../../service/user-login.service"; 5 | import {CognitoCallback} from "../../../service/cognito.service"; 6 | 7 | export class NewPasswordUser { 8 | username: string; 9 | existingPassword: string; 10 | password: string; 11 | } 12 | /** 13 | * This component is responsible for displaying and controlling 14 | * the registration of the user. 15 | */ 16 | @Component({ 17 | selector: 'awscognito-angular2-app', 18 | templateUrl: './newpassword.html' 19 | }) 20 | export class NewPasswordComponent implements CognitoCallback { 21 | registrationUser: NewPasswordUser; 22 | router: Router; 23 | errorMessage: string; 24 | 25 | constructor(public userRegistration: UserRegistrationService, public userService: UserLoginService, router: Router) { 26 | this.router = router; 27 | this.onInit(); 28 | } 29 | 30 | onInit() { 31 | this.registrationUser = new NewPasswordUser(); 32 | this.errorMessage = null; 33 | } 34 | 35 | ngOnInit() { 36 | this.errorMessage = null; 37 | console.log("Checking if the user is already authenticated. If so, then redirect to the secure site"); 38 | this.userService.isAuthenticated(this); 39 | } 40 | 41 | onRegister() { 42 | console.log(this.registrationUser); 43 | this.errorMessage = null; 44 | this.userRegistration.newPassword(this.registrationUser, this); 45 | } 46 | 47 | cognitoCallback(message: string, result: any) { 48 | if (message != null) { //error 49 | this.errorMessage = message; 50 | console.log("result: " + this.errorMessage); 51 | } else { //success 52 | //move to the next step 53 | console.log("redirecting"); 54 | this.router.navigate(['/securehome']); 55 | } 56 | } 57 | 58 | isLoggedIn(message: string, isLoggedIn: boolean) { 59 | if (isLoggedIn) 60 | this.router.navigate(['/securehome']); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/public/auth/newpassword/newpassword.html: -------------------------------------------------------------------------------- 1 | 33 | -------------------------------------------------------------------------------- /src/app/public/auth/register/registration.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {Router} from "@angular/router"; 3 | import {UserRegistrationService} from "../../../service/user-registration.service"; 4 | import {CognitoCallback} from "../../../service/cognito.service"; 5 | 6 | export class RegistrationUser { 7 | name: string; 8 | email: string; 9 | phone_number: string; 10 | password: string; 11 | } 12 | /** 13 | * This component is responsible for displaying and controlling 14 | * the registration of the user. 15 | */ 16 | @Component({ 17 | selector: 'awscognito-angular2-app', 18 | templateUrl: './registration.html' 19 | }) 20 | export class RegisterComponent implements CognitoCallback { 21 | registrationUser: RegistrationUser; 22 | router: Router; 23 | errorMessage: string; 24 | 25 | constructor(public userRegistration: UserRegistrationService, router: Router) { 26 | this.router = router; 27 | this.onInit(); 28 | } 29 | 30 | onInit() { 31 | this.registrationUser = new RegistrationUser(); 32 | this.errorMessage = null; 33 | } 34 | 35 | onRegister() { 36 | this.errorMessage = null; 37 | this.userRegistration.register(this.registrationUser, this); 38 | } 39 | 40 | cognitoCallback(message: string, result: any) { 41 | if (message != null) { //error 42 | this.errorMessage = message; 43 | console.log("result: " + this.errorMessage); 44 | } else { //success 45 | //move to the next step 46 | console.log("redirecting"); 47 | this.router.navigate(['/home/confirmRegistration', result.user.username]); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/public/auth/register/registration.html: -------------------------------------------------------------------------------- 1 | 37 | 38 | -------------------------------------------------------------------------------- /src/app/public/auth/resend/resendCode.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {UserRegistrationService} from "../../../service/user-registration.service"; 3 | import {CognitoCallback} from "../../../service/cognito.service"; 4 | import {Router} from "@angular/router"; 5 | @Component({ 6 | selector: 'awscognito-angular2-app', 7 | templateUrl: './resendCode.html' 8 | }) 9 | export class ResendCodeComponent implements CognitoCallback { 10 | 11 | email: string; 12 | errorMessage: string; 13 | 14 | constructor(public registrationService: UserRegistrationService, public router: Router) { 15 | 16 | } 17 | 18 | resendCode() { 19 | this.registrationService.resendCode(this.email, this); 20 | } 21 | 22 | cognitoCallback(error: any, result: any) { 23 | if (error != null) { 24 | this.errorMessage = "Something went wrong...please try again"; 25 | } else { 26 | this.router.navigate(['/home/confirmRegistration', this.email]); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/app/public/auth/resend/resendCode.html: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /src/app/public/home.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from "@angular/core"; 2 | 3 | declare let AWS: any; 4 | declare let AWSCognito: any; 5 | 6 | @Component({ 7 | selector: 'awscognito-angular2-app', 8 | template: '

Hello and welcome!"

' 9 | }) 10 | export class AboutComponent { 11 | 12 | } 13 | 14 | @Component({ 15 | selector: 'awscognito-angular2-app', 16 | templateUrl: './landinghome.html' 17 | }) 18 | export class HomeLandingComponent { 19 | constructor() { 20 | console.log("HomeLandingComponent constructor"); 21 | } 22 | } 23 | 24 | @Component({ 25 | selector: 'awscognito-angular2-app', 26 | templateUrl: './home.html' 27 | }) 28 | export class HomeComponent implements OnInit { 29 | 30 | constructor() { 31 | console.log("HomeComponent constructor"); 32 | } 33 | 34 | ngOnInit() { 35 | 36 | } 37 | } 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/app/public/home.html: -------------------------------------------------------------------------------- 1 | 2 | 30 |
31 | 32 |
33 | 34 | -------------------------------------------------------------------------------- /src/app/public/landinghome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 | 6 |
7 |
8 |
9 |

Cognito QuickStart App

10 |

Source code can be found here 11 |

12 |
13 | 20 |
21 |
22 |
23 | 24 |
25 | 26 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /src/app/secure/jwttokens/jwt.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {UserLoginService} from "../../service/user-login.service"; 3 | import {Callback, CognitoUtil, LoggedInCallback} from "../../service/cognito.service"; 4 | import {Router} from "@angular/router"; 5 | 6 | 7 | export class Stuff { 8 | public accessToken: string; 9 | public idToken: string; 10 | } 11 | 12 | @Component({ 13 | selector: 'awscognito-angular2-app', 14 | templateUrl: './jwt.html' 15 | }) 16 | export class JwtComponent implements LoggedInCallback { 17 | 18 | public stuff: Stuff = new Stuff(); 19 | 20 | constructor(public router: Router, public userService: UserLoginService, public cognitoUtil: CognitoUtil) { 21 | this.userService.isAuthenticated(this); 22 | console.log("in JwtComponent"); 23 | 24 | } 25 | 26 | isLoggedIn(message: string, isLoggedIn: boolean) { 27 | if (!isLoggedIn) { 28 | this.router.navigate(['/home/login']); 29 | } else { 30 | this.cognitoUtil.getAccessToken(new AccessTokenCallback(this)); 31 | this.cognitoUtil.getIdToken(new IdTokenCallback(this)); 32 | } 33 | } 34 | } 35 | 36 | export class AccessTokenCallback implements Callback { 37 | constructor(public jwt: JwtComponent) { 38 | 39 | } 40 | 41 | callback() { 42 | 43 | } 44 | 45 | callbackWithParam(result) { 46 | this.jwt.stuff.accessToken = result; 47 | } 48 | } 49 | 50 | export class IdTokenCallback implements Callback { 51 | constructor(public jwt: JwtComponent) { 52 | 53 | } 54 | 55 | callback() { 56 | 57 | } 58 | 59 | callbackWithParam(result) { 60 | this.jwt.stuff.idToken = result; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/app/secure/jwttokens/jwt.html: -------------------------------------------------------------------------------- 1 |

JWT Tokens

2 | 6 | 7 |
8 |
9 |

Access Token

10 |

{{ stuff.accessToken }}

11 |
12 |
13 |

Id Token

14 |

{{ stuff.idToken }}

15 |
16 |
17 | -------------------------------------------------------------------------------- /src/app/secure/landing/secureHome.css: -------------------------------------------------------------------------------- 1 | body, 2 | html { 3 | width: 100%; 4 | height: 100%; 5 | 6 | background: no-repeat center center; 7 | background-size: cover; 8 | } -------------------------------------------------------------------------------- /src/app/secure/landing/secureHome.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 55 | 56 | 57 |
58 |
59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | 67 |
68 | 69 |
70 | 71 | 72 |
73 | 74 | -------------------------------------------------------------------------------- /src/app/secure/landing/securehome.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from "@angular/core"; 2 | import {Router} from "@angular/router"; 3 | import {UserLoginService} from "../../service/user-login.service"; 4 | import {LoggedInCallback} from "../../service/cognito.service"; 5 | 6 | @Component({ 7 | selector: 'awscognito-angular2-app', 8 | templateUrl: './secureHome.html' 9 | // styleUrls: ['/assets/css/sb-admin.css'] 10 | }) 11 | export class SecureHomeComponent implements OnInit, LoggedInCallback { 12 | 13 | constructor(public router: Router, public userService: UserLoginService) { 14 | this.userService.isAuthenticated(this); 15 | console.log("SecureHomeComponent: constructor"); 16 | } 17 | 18 | ngOnInit() { 19 | 20 | } 21 | 22 | isLoggedIn(message: string, isLoggedIn: boolean) { 23 | if (!isLoggedIn) { 24 | this.router.navigate(['/home/login']); 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/app/secure/profile/myprofile.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {UserLoginService} from "../../service/user-login.service"; 3 | import {Callback, CognitoUtil, LoggedInCallback} from "../../service/cognito.service"; 4 | import {UserParametersService} from "../../service/user-parameters.service"; 5 | import {Router} from "@angular/router"; 6 | 7 | 8 | @Component({ 9 | selector: 'awscognito-angular2-app', 10 | templateUrl: './myprofile.html' 11 | }) 12 | export class MyProfileComponent implements LoggedInCallback { 13 | 14 | public parameters: Array = []; 15 | public cognitoId: String; 16 | 17 | constructor(public router: Router, public userService: UserLoginService, public userParams: UserParametersService, public cognitoUtil: CognitoUtil) { 18 | this.userService.isAuthenticated(this); 19 | console.log("In MyProfileComponent"); 20 | } 21 | 22 | isLoggedIn(message: string, isLoggedIn: boolean) { 23 | if (!isLoggedIn) { 24 | this.router.navigate(['/home/login']); 25 | } else { 26 | this.userParams.getParameters(new GetParametersCallback(this, this.cognitoUtil)); 27 | } 28 | } 29 | } 30 | 31 | export class Parameters { 32 | name: string; 33 | value: string; 34 | } 35 | 36 | export class GetParametersCallback implements Callback { 37 | 38 | constructor(public me: MyProfileComponent, public cognitoUtil: CognitoUtil) { 39 | 40 | } 41 | 42 | callback() { 43 | 44 | } 45 | 46 | callbackWithParam(result: any) { 47 | 48 | for (let i = 0; i < result.length; i++) { 49 | let parameter = new Parameters(); 50 | parameter.name = result[i].getName(); 51 | parameter.value = result[i].getValue(); 52 | this.me.parameters.push(parameter); 53 | } 54 | let param = new Parameters() 55 | param.name = "cognito ID"; 56 | param.value = this.cognitoUtil.getCognitoIdentity(); 57 | this.me.parameters.push(param) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/app/secure/profile/myprofile.html: -------------------------------------------------------------------------------- 1 |

My Profile Parameters

2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
NameValue
{{ parameter.name }}{{ parameter.value }}
15 |
16 | -------------------------------------------------------------------------------- /src/app/secure/useractivity/useractivity.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {UserLoginService} from "../../service/user-login.service"; 3 | import {LoggedInCallback} from "../../service/cognito.service"; 4 | import {Router} from "@angular/router"; 5 | import {DynamoDBService} from "../../service/ddb.service"; 6 | 7 | 8 | export class Stuff { 9 | public type: string; 10 | public date: string; 11 | } 12 | 13 | @Component({ 14 | selector: 'awscognito-angular2-app', 15 | templateUrl: './useractivity.html' 16 | }) 17 | export class UseractivityComponent implements LoggedInCallback { 18 | 19 | public logdata: Array = []; 20 | 21 | constructor(public router: Router, public ddb: DynamoDBService, public userService: UserLoginService) { 22 | this.userService.isAuthenticated(this); 23 | console.log("in UseractivityComponent"); 24 | } 25 | 26 | isLoggedIn(message: string, isLoggedIn: boolean) { 27 | if (!isLoggedIn) { 28 | this.router.navigate(['/home/login']); 29 | } else { 30 | console.log("scanning DDB"); 31 | this.ddb.getLogEntries(this.logdata); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/app/secure/useractivity/useractivity.html: -------------------------------------------------------------------------------- 1 |

My Login Activity

2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
ActionDate
{{ item.type }}{{ item.date }}
14 |
15 | -------------------------------------------------------------------------------- /src/app/service/aws.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from "@angular/core"; 2 | import {Callback, CognitoUtil} from "./cognito.service"; 3 | import * as AWS from "aws-sdk/global"; 4 | 5 | /** 6 | * Created by Vladimir Budilov 7 | */ 8 | 9 | // declare var AMA: any; 10 | 11 | @Injectable() 12 | export class AwsUtil { 13 | public static firstLogin: boolean = false; 14 | public static runningInit: boolean = false; 15 | 16 | constructor(public cognitoUtil: CognitoUtil) { 17 | AWS.config.region = CognitoUtil._REGION; 18 | } 19 | 20 | /** 21 | * This is the method that needs to be called in order to init the aws global creds 22 | */ 23 | initAwsService(callback: Callback, isLoggedIn: boolean, idToken: string) { 24 | 25 | if (AwsUtil.runningInit) { 26 | // Need to make sure I don't get into an infinite loop here, so need to exit if this method is running already 27 | console.log("AwsUtil: Aborting running initAwsService()...it's running already."); 28 | // instead of aborting here, it's best to put a timer 29 | if (callback != null) { 30 | callback.callback(); 31 | callback.callbackWithParam(null); 32 | } 33 | return; 34 | } 35 | 36 | 37 | console.log("AwsUtil: Running initAwsService()"); 38 | AwsUtil.runningInit = true; 39 | 40 | 41 | let mythis = this; 42 | // First check if the user is authenticated already 43 | if (isLoggedIn) 44 | mythis.setupAWS(isLoggedIn, callback, idToken); 45 | 46 | } 47 | 48 | 49 | /** 50 | * Sets up the AWS global params 51 | * 52 | * @param isLoggedIn 53 | * @param callback 54 | */ 55 | setupAWS(isLoggedIn: boolean, callback: Callback, idToken: string): void { 56 | console.log("AwsUtil: in setupAWS()"); 57 | if (isLoggedIn) { 58 | console.log("AwsUtil: User is logged in"); 59 | // Setup mobile analytics 60 | var options = { 61 | appId: '32673c035a0b40e99d6e1f327be0cb60', 62 | appTitle: "aws-cognito-angular2-quickstart" 63 | }; 64 | 65 | // TODO: The mobile Analytics client needs some work to handle Typescript. Disabling for the time being. 66 | // var mobileAnalyticsClient = new AMA.Manager(options); 67 | // mobileAnalyticsClient.submitEvents(); 68 | 69 | this.addCognitoCredentials(idToken); 70 | 71 | console.log("AwsUtil: Retrieving the id token"); 72 | 73 | } 74 | else { 75 | console.log("AwsUtil: User is not logged in"); 76 | } 77 | 78 | if (callback != null) { 79 | callback.callback(); 80 | callback.callbackWithParam(null); 81 | } 82 | 83 | AwsUtil.runningInit = false; 84 | } 85 | 86 | addCognitoCredentials(idTokenJwt: string): void { 87 | let creds = this.cognitoUtil.buildCognitoCreds(idTokenJwt); 88 | 89 | AWS.config.credentials = creds; 90 | 91 | creds.get(function (err) { 92 | if (!err) { 93 | if (AwsUtil.firstLogin) { 94 | // save the login info to DDB 95 | this.ddb.writeLogEntry("login"); 96 | AwsUtil.firstLogin = false; 97 | } 98 | } 99 | }); 100 | } 101 | 102 | static getCognitoParametersForIdConsolidation(idTokenJwt: string): {} { 103 | console.log("AwsUtil: enter getCognitoParametersForIdConsolidation()"); 104 | let url = 'cognito-idp.' + CognitoUtil._REGION.toLowerCase() + '.amazonaws.com/' + CognitoUtil._USER_POOL_ID; 105 | let logins: Array = []; 106 | logins[url] = idTokenJwt; 107 | let params = { 108 | IdentityPoolId: CognitoUtil._IDENTITY_POOL_ID, /* required */ 109 | Logins: logins 110 | }; 111 | 112 | return params; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/app/service/cognito.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@angular/core"; 2 | import { environment } from "../../environments/environment"; 3 | import { CognitoUserPool } from "amazon-cognito-identity-js"; 4 | import * as AWS from "aws-sdk/global"; 5 | import * as awsservice from "aws-sdk/lib/service"; 6 | import * as CognitoIdentity from "aws-sdk/clients/cognitoidentity"; 7 | 8 | 9 | /** 10 | * Created by Vladimir Budilov 11 | */ 12 | 13 | export interface CognitoCallback { 14 | cognitoCallback(message: string, result: any): void; 15 | 16 | handleMFAStep?(challengeName: string, challengeParameters: ChallengeParameters, callback: (confirmationCode: string) => any): void; 17 | } 18 | 19 | export interface LoggedInCallback { 20 | isLoggedIn(message: string, loggedIn: boolean): void; 21 | } 22 | 23 | export interface ChallengeParameters { 24 | CODE_DELIVERY_DELIVERY_MEDIUM: string; 25 | 26 | CODE_DELIVERY_DESTINATION: string; 27 | } 28 | 29 | export interface Callback { 30 | callback(): void; 31 | 32 | callbackWithParam(result: any): void; 33 | } 34 | 35 | @Injectable() 36 | export class CognitoUtil { 37 | 38 | public static _REGION = environment.region; 39 | 40 | public static _IDENTITY_POOL_ID = environment.identityPoolId; 41 | public static _USER_POOL_ID = environment.userPoolId; 42 | public static _CLIENT_ID = environment.clientId; 43 | 44 | public static _POOL_DATA: any = { 45 | UserPoolId: CognitoUtil._USER_POOL_ID, 46 | ClientId: CognitoUtil._CLIENT_ID 47 | }; 48 | 49 | public cognitoCreds: AWS.CognitoIdentityCredentials; 50 | 51 | getUserPool() { 52 | if (environment.cognito_idp_endpoint) { 53 | CognitoUtil._POOL_DATA.endpoint = environment.cognito_idp_endpoint; 54 | } 55 | return new CognitoUserPool(CognitoUtil._POOL_DATA); 56 | } 57 | 58 | getCurrentUser() { 59 | return this.getUserPool().getCurrentUser(); 60 | } 61 | 62 | // AWS Stores Credentials in many ways, and with TypeScript this means that 63 | // getting the base credentials we authenticated with from the AWS globals gets really murky, 64 | // having to get around both class extension and unions. Therefore, we're going to give 65 | // developers direct access to the raw, unadulterated CognitoIdentityCredentials 66 | // object at all times. 67 | setCognitoCreds(creds: AWS.CognitoIdentityCredentials) { 68 | this.cognitoCreds = creds; 69 | } 70 | 71 | getCognitoCreds() { 72 | return this.cognitoCreds; 73 | } 74 | 75 | // This method takes in a raw jwtToken and uses the global AWS config options to build a 76 | // CognitoIdentityCredentials object and store it for us. It also returns the object to the caller 77 | // to avoid unnecessary calls to setCognitoCreds. 78 | 79 | buildCognitoCreds(idTokenJwt: string) { 80 | let url = 'cognito-idp.' + CognitoUtil._REGION.toLowerCase() + '.amazonaws.com/' + CognitoUtil._USER_POOL_ID; 81 | if (environment.cognito_idp_endpoint) { 82 | url = environment.cognito_idp_endpoint + '/' + CognitoUtil._USER_POOL_ID; 83 | } 84 | let logins: CognitoIdentity.LoginsMap = {}; 85 | logins[url] = idTokenJwt; 86 | let params = { 87 | IdentityPoolId: CognitoUtil._IDENTITY_POOL_ID, /* required */ 88 | Logins: logins 89 | }; 90 | let serviceConfigs = {}; 91 | if (environment.cognito_identity_endpoint) { 92 | serviceConfigs.endpoint = environment.cognito_identity_endpoint; 93 | } 94 | let creds = new AWS.CognitoIdentityCredentials(params, serviceConfigs); 95 | this.setCognitoCreds(creds); 96 | return creds; 97 | } 98 | 99 | 100 | getCognitoIdentity(): string { 101 | return this.cognitoCreds.identityId; 102 | } 103 | 104 | getAccessToken(callback: Callback): void { 105 | if (callback == null) { 106 | throw("CognitoUtil: callback in getAccessToken is null...returning"); 107 | } 108 | if (this.getCurrentUser() != null) { 109 | this.getCurrentUser().getSession(function (err, session) { 110 | if (err) { 111 | console.log("CognitoUtil: Can't set the credentials:" + err); 112 | callback.callbackWithParam(null); 113 | } 114 | else { 115 | if (session.isValid()) { 116 | callback.callbackWithParam(session.getAccessToken().getJwtToken()); 117 | } 118 | } 119 | }); 120 | } 121 | else { 122 | callback.callbackWithParam(null); 123 | } 124 | } 125 | 126 | getIdToken(callback: Callback): void { 127 | if (callback == null) { 128 | throw("CognitoUtil: callback in getIdToken is null...returning"); 129 | } 130 | if (this.getCurrentUser() != null) 131 | this.getCurrentUser().getSession(function (err, session) { 132 | if (err) { 133 | console.log("CognitoUtil: Can't set the credentials:" + err); 134 | callback.callbackWithParam(null); 135 | } 136 | else { 137 | if (session.isValid()) { 138 | callback.callbackWithParam(session.getIdToken().getJwtToken()); 139 | } else { 140 | console.log("CognitoUtil: Got the id token, but the session isn't valid"); 141 | } 142 | } 143 | }); 144 | else 145 | callback.callbackWithParam(null); 146 | } 147 | 148 | getRefreshToken(callback: Callback): void { 149 | if (callback == null) { 150 | throw("CognitoUtil: callback in getRefreshToken is null...returning"); 151 | } 152 | if (this.getCurrentUser() != null) 153 | this.getCurrentUser().getSession(function (err, session) { 154 | if (err) { 155 | console.log("CognitoUtil: Can't set the credentials:" + err); 156 | callback.callbackWithParam(null); 157 | } 158 | 159 | else { 160 | if (session.isValid()) { 161 | callback.callbackWithParam(session.getRefreshToken()); 162 | } 163 | } 164 | }); 165 | else 166 | callback.callbackWithParam(null); 167 | } 168 | 169 | refresh(): void { 170 | this.getCurrentUser().getSession(function (err, session) { 171 | if (err) { 172 | console.log("CognitoUtil: Can't set the credentials:" + err); 173 | } 174 | 175 | else { 176 | if (session.isValid()) { 177 | console.log("CognitoUtil: refreshed successfully"); 178 | } else { 179 | console.log("CognitoUtil: refreshed but session is still not valid"); 180 | } 181 | } 182 | }); 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/app/service/ddb.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from "@angular/core"; 2 | import {CognitoUtil} from "./cognito.service"; 3 | import {environment} from "../../environments/environment"; 4 | 5 | import {Stuff} from "../secure/useractivity/useractivity.component"; 6 | import * as AWS from "aws-sdk/global"; 7 | import * as DynamoDB from "aws-sdk/clients/dynamodb"; 8 | 9 | /** 10 | * Created by Vladimir Budilov 11 | */ 12 | 13 | @Injectable() 14 | export class DynamoDBService { 15 | 16 | constructor(public cognitoUtil: CognitoUtil) { 17 | console.log("DynamoDBService: constructor"); 18 | } 19 | 20 | getAWS() { 21 | return AWS; 22 | } 23 | 24 | getLogEntries(mapArray: Array) { 25 | console.log("DynamoDBService: reading from DDB with creds - " + AWS.config.credentials); 26 | var params = { 27 | TableName: environment.ddbTableName, 28 | KeyConditionExpression: "userId = :userId", 29 | ExpressionAttributeValues: { 30 | ":userId": this.cognitoUtil.getCognitoIdentity() 31 | } 32 | }; 33 | 34 | var clientParams:any = {}; 35 | if (environment.dynamodb_endpoint) { 36 | clientParams.endpoint = environment.dynamodb_endpoint; 37 | } 38 | var docClient = new DynamoDB.DocumentClient(clientParams); 39 | docClient.query(params, onQuery); 40 | 41 | function onQuery(err, data) { 42 | if (err) { 43 | console.error("DynamoDBService: Unable to query the table. Error JSON:", JSON.stringify(err, null, 2)); 44 | } else { 45 | // print all the movies 46 | console.log("DynamoDBService: Query succeeded."); 47 | data.Items.forEach(function (logitem) { 48 | mapArray.push({type: logitem.type, date: logitem.activityDate}); 49 | }); 50 | } 51 | } 52 | } 53 | 54 | writeLogEntry(type: string) { 55 | try { 56 | let date = new Date().toString(); 57 | console.log("DynamoDBService: Writing log entry. Type:" + type + " ID: " + this.cognitoUtil.getCognitoIdentity() + " Date: " + date); 58 | this.write(this.cognitoUtil.getCognitoIdentity(), date, type); 59 | } catch (exc) { 60 | console.log("DynamoDBService: Couldn't write to DDB"); 61 | } 62 | 63 | } 64 | 65 | write(data: string, date: string, type: string): void { 66 | console.log("DynamoDBService: writing " + type + " entry"); 67 | 68 | let clientParams:any = { 69 | params: {TableName: environment.ddbTableName} 70 | }; 71 | if (environment.dynamodb_endpoint) { 72 | clientParams.endpoint = environment.dynamodb_endpoint; 73 | } 74 | var DDB = new DynamoDB(clientParams); 75 | 76 | // Write the item to the table 77 | var itemParams = 78 | { 79 | TableName: environment.ddbTableName, 80 | Item: { 81 | userId: {S: data}, 82 | activityDate: {S: date}, 83 | type: {S: type} 84 | } 85 | }; 86 | DDB.putItem(itemParams, function (result) { 87 | console.log("DynamoDBService: wrote entry: " + JSON.stringify(result)); 88 | }); 89 | } 90 | 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/app/service/s3.service.ts: -------------------------------------------------------------------------------- 1 | import {environment} from "../../environments/environment"; 2 | import {CognitoUtil} from "./cognito.service"; 3 | import * as AWS from "aws-sdk/global"; 4 | import * as S3 from "aws-sdk/clients/s3"; 5 | 6 | /** 7 | * Created by Vladimir Budilov 8 | */ 9 | 10 | 11 | export class S3Service { 12 | 13 | constructor(public cognitoUtil: CognitoUtil) { 14 | 15 | } 16 | 17 | private getS3(): any { 18 | AWS.config.update({ 19 | region: environment.bucketRegion, 20 | }); 21 | 22 | let clientParams:any = { 23 | region: environment.bucketRegion, 24 | apiVersion: '2006-03-01', 25 | params: {Bucket: environment.rekognitionBucket} 26 | }; 27 | if (environment.s3_endpoint) { 28 | clientParams.endpoint = environment.s3_endpoint; 29 | } 30 | var s3 = new S3(clientParams); 31 | 32 | return s3 33 | } 34 | 35 | public addPhoto(selectedFile): boolean { 36 | if (!selectedFile) { 37 | console.log('Please choose a file to upload first.'); 38 | return; 39 | } 40 | let fileName = selectedFile.name; 41 | let albumPhotosKey = environment.albumName + '/' + this.cognitoUtil.getCognitoIdentity() + "/"; 42 | let photoKey = albumPhotosKey + fileName; 43 | 44 | this.getS3().upload({ 45 | Key: photoKey, 46 | ContentType: selectedFile.type, 47 | Body: selectedFile, 48 | StorageClass: 'STANDARD', 49 | ACL: 'private' 50 | }, function (err, data) { 51 | if (err) { 52 | console.log('There was an error uploading your photo: ', err); 53 | return false; 54 | } 55 | console.log('Successfully uploaded photo.'); 56 | return true; 57 | }); 58 | } 59 | 60 | public deletePhoto(albumName, photoKey) { 61 | // this.getS3().deleteObjectStore("").promise().then(function () { 62 | // 63 | // } 64 | this.getS3().deleteObject({Key: photoKey}, function (err, data) { 65 | if (err) { 66 | console.log('There was an error deleting your photo: ', err.message); 67 | return; 68 | } 69 | console.log('Successfully deleted photo.'); 70 | }); 71 | } 72 | 73 | public viewAlbum(albumName) { 74 | var albumPhotosKey = encodeURIComponent(environment.albumName) + '//'; 75 | this.getS3().listObjects({Prefix: albumPhotosKey}, function (err, data) { 76 | if (err) { 77 | console.log('There was an error viewing your album: ' + err); 78 | } 79 | 80 | }); 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /src/app/service/user-login.service.ts: -------------------------------------------------------------------------------- 1 | import { environment } from "../../environments/environment"; 2 | import { Injectable } from "@angular/core"; 3 | import { DynamoDBService } from "./ddb.service"; 4 | import { CognitoCallback, CognitoUtil, LoggedInCallback } from "./cognito.service"; 5 | import { AuthenticationDetails, CognitoUser, CognitoUserSession } from "amazon-cognito-identity-js"; 6 | import * as AWS from "aws-sdk/global"; 7 | import * as STS from "aws-sdk/clients/sts"; 8 | 9 | @Injectable() 10 | export class UserLoginService { 11 | 12 | private onLoginSuccess = (callback: CognitoCallback, session: CognitoUserSession) => { 13 | 14 | console.log("In authenticateUser onSuccess callback"); 15 | 16 | AWS.config.credentials = this.cognitoUtil.buildCognitoCreds(session.getIdToken().getJwtToken()); 17 | 18 | // So, when CognitoIdentity authenticates a user, it doesn't actually hand us the IdentityID, 19 | // used by many of our other handlers. This is handled by some sly underhanded calls to AWS Cognito 20 | // API's by the SDK itself, automatically when the first AWS SDK request is made that requires our 21 | // security credentials. The identity is then injected directly into the credentials object. 22 | // If the first SDK call we make wants to use our IdentityID, we have a 23 | // chicken and egg problem on our hands. We resolve this problem by "priming" the AWS SDK by calling a 24 | // very innocuous API call that forces this behavior. 25 | let clientParams: any = {}; 26 | if (environment.sts_endpoint) { 27 | clientParams.endpoint = environment.sts_endpoint; 28 | } 29 | let sts = new STS(clientParams); 30 | sts.getCallerIdentity(function (err, data) { 31 | console.log("UserLoginService: Successfully set the AWS credentials"); 32 | callback.cognitoCallback(null, session); 33 | }); 34 | } 35 | 36 | private onLoginError = (callback: CognitoCallback, err) => { 37 | callback.cognitoCallback(err.message, null); 38 | } 39 | 40 | constructor(public ddb: DynamoDBService, public cognitoUtil: CognitoUtil) { 41 | } 42 | 43 | authenticate(username: string, password: string, callback: CognitoCallback) { 44 | console.log("UserLoginService: starting the authentication"); 45 | 46 | let authenticationData = { 47 | Username: username, 48 | Password: password, 49 | }; 50 | let authenticationDetails = new AuthenticationDetails(authenticationData); 51 | 52 | let userData = { 53 | Username: username, 54 | Pool: this.cognitoUtil.getUserPool() 55 | }; 56 | 57 | console.log("UserLoginService: Params set...Authenticating the user"); 58 | let cognitoUser = new CognitoUser(userData); 59 | console.log("UserLoginService: config is " + AWS.config); 60 | cognitoUser.authenticateUser(authenticationDetails, { 61 | newPasswordRequired: (userAttributes, requiredAttributes) => callback.cognitoCallback(`User needs to set password.`, null), 62 | onSuccess: result => this.onLoginSuccess(callback, result), 63 | onFailure: err => this.onLoginError(callback, err), 64 | mfaRequired: (challengeName, challengeParameters) => { 65 | callback.handleMFAStep(challengeName, challengeParameters, (confirmationCode: string) => { 66 | cognitoUser.sendMFACode(confirmationCode, { 67 | onSuccess: result => this.onLoginSuccess(callback, result), 68 | onFailure: err => this.onLoginError(callback, err) 69 | }); 70 | }); 71 | } 72 | }); 73 | } 74 | 75 | forgotPassword(username: string, callback: CognitoCallback) { 76 | let userData = { 77 | Username: username, 78 | Pool: this.cognitoUtil.getUserPool() 79 | }; 80 | 81 | let cognitoUser = new CognitoUser(userData); 82 | 83 | cognitoUser.forgotPassword({ 84 | onSuccess: function () { 85 | 86 | }, 87 | onFailure: function (err) { 88 | callback.cognitoCallback(err.message, null); 89 | }, 90 | inputVerificationCode() { 91 | callback.cognitoCallback(null, null); 92 | } 93 | }); 94 | } 95 | 96 | confirmNewPassword(email: string, verificationCode: string, password: string, callback: CognitoCallback) { 97 | let userData = { 98 | Username: email, 99 | Pool: this.cognitoUtil.getUserPool() 100 | }; 101 | 102 | let cognitoUser = new CognitoUser(userData); 103 | 104 | cognitoUser.confirmPassword(verificationCode, password, { 105 | onSuccess: function () { 106 | callback.cognitoCallback(null, null); 107 | }, 108 | onFailure: function (err) { 109 | callback.cognitoCallback(err.message, null); 110 | } 111 | }); 112 | } 113 | 114 | logout() { 115 | console.log("UserLoginService: Logging out"); 116 | this.ddb.writeLogEntry("logout"); 117 | this.cognitoUtil.getCurrentUser().signOut(); 118 | 119 | } 120 | 121 | isAuthenticated(callback: LoggedInCallback) { 122 | if (callback == null) 123 | throw("UserLoginService: Callback in isAuthenticated() cannot be null"); 124 | 125 | let cognitoUser = this.cognitoUtil.getCurrentUser(); 126 | 127 | if (cognitoUser != null) { 128 | cognitoUser.getSession(function (err, session) { 129 | if (err) { 130 | console.log("UserLoginService: Couldn't get the session: " + err, err.stack); 131 | callback.isLoggedIn(err, false); 132 | } 133 | else { 134 | console.log("UserLoginService: Session is " + session.isValid()); 135 | callback.isLoggedIn(err, session.isValid()); 136 | } 137 | }); 138 | } else { 139 | console.log("UserLoginService: can't retrieve the current user"); 140 | callback.isLoggedIn("Can't retrieve the CurrentUser", false); 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/app/service/user-parameters.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from "@angular/core"; 2 | import {Callback, CognitoUtil} from "./cognito.service"; 3 | 4 | @Injectable() 5 | export class UserParametersService { 6 | 7 | constructor(public cognitoUtil: CognitoUtil) { 8 | } 9 | 10 | getParameters(callback: Callback) { 11 | let cognitoUser = this.cognitoUtil.getCurrentUser(); 12 | 13 | if (cognitoUser != null) { 14 | cognitoUser.getSession(function (err, session) { 15 | if (err) 16 | console.log("UserParametersService: Couldn't retrieve the user"); 17 | else { 18 | cognitoUser.getUserAttributes(function (err, result) { 19 | if (err) { 20 | console.log("UserParametersService: in getParameters: " + err); 21 | } else { 22 | callback.callbackWithParam(result); 23 | } 24 | }); 25 | } 26 | 27 | }); 28 | } else { 29 | callback.callbackWithParam(null); 30 | } 31 | 32 | 33 | } 34 | } -------------------------------------------------------------------------------- /src/app/service/user-registration.service.ts: -------------------------------------------------------------------------------- 1 | import {Inject, Injectable} from "@angular/core"; 2 | import {CognitoCallback, CognitoUtil} from "./cognito.service"; 3 | import {AuthenticationDetails, CognitoUser, CognitoUserAttribute} from "amazon-cognito-identity-js"; 4 | import {RegistrationUser} from "../public/auth/register/registration.component"; 5 | import {NewPasswordUser} from "../public/auth/newpassword/newpassword.component"; 6 | import * as AWS from "aws-sdk/global"; 7 | 8 | @Injectable() 9 | export class UserRegistrationService { 10 | 11 | constructor(@Inject(CognitoUtil) public cognitoUtil: CognitoUtil) { 12 | 13 | } 14 | 15 | register(user: RegistrationUser, callback: CognitoCallback): void { 16 | console.log("UserRegistrationService: user is " + user); 17 | 18 | let attributeList = []; 19 | 20 | let dataEmail = { 21 | Name: 'email', 22 | Value: user.email 23 | }; 24 | let dataNickname = { 25 | Name: 'nickname', 26 | Value: user.name 27 | }; 28 | attributeList.push(new CognitoUserAttribute(dataEmail)); 29 | attributeList.push(new CognitoUserAttribute(dataNickname)); 30 | attributeList.push(new CognitoUserAttribute({ 31 | Name: 'phone_number', 32 | Value: user.phone_number 33 | })); 34 | 35 | this.cognitoUtil.getUserPool().signUp(user.email, user.password, attributeList, null, function (err, result) { 36 | if (err) { 37 | callback.cognitoCallback(err.message, null); 38 | } else { 39 | console.log("UserRegistrationService: registered user is " + result); 40 | callback.cognitoCallback(null, result); 41 | } 42 | }); 43 | 44 | } 45 | 46 | confirmRegistration(username: string, confirmationCode: string, callback: CognitoCallback): void { 47 | 48 | let userData = { 49 | Username: username, 50 | Pool: this.cognitoUtil.getUserPool() 51 | }; 52 | 53 | let cognitoUser = new CognitoUser(userData); 54 | 55 | cognitoUser.confirmRegistration(confirmationCode, true, function (err, result) { 56 | if (err) { 57 | callback.cognitoCallback(err.message, null); 58 | } else { 59 | callback.cognitoCallback(null, result); 60 | } 61 | }); 62 | } 63 | 64 | resendCode(username: string, callback: CognitoCallback): void { 65 | let userData = { 66 | Username: username, 67 | Pool: this.cognitoUtil.getUserPool() 68 | }; 69 | 70 | let cognitoUser = new CognitoUser(userData); 71 | 72 | cognitoUser.resendConfirmationCode(function (err, result) { 73 | if (err) { 74 | callback.cognitoCallback(err.message, null); 75 | } else { 76 | callback.cognitoCallback(null, result); 77 | } 78 | }); 79 | } 80 | 81 | newPassword(newPasswordUser: NewPasswordUser, callback: CognitoCallback): void { 82 | console.log(newPasswordUser); 83 | // Get these details and call 84 | //cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this); 85 | let authenticationData = { 86 | Username: newPasswordUser.username, 87 | Password: newPasswordUser.existingPassword, 88 | }; 89 | let authenticationDetails = new AuthenticationDetails(authenticationData); 90 | 91 | let userData = { 92 | Username: newPasswordUser.username, 93 | Pool: this.cognitoUtil.getUserPool() 94 | }; 95 | 96 | console.log("UserLoginService: Params set...Authenticating the user"); 97 | let cognitoUser = new CognitoUser(userData); 98 | console.log("UserLoginService: config is " + AWS.config); 99 | cognitoUser.authenticateUser(authenticationDetails, { 100 | newPasswordRequired: function (userAttributes, requiredAttributes) { 101 | // User was signed up by an admin and must provide new 102 | // password and required attributes, if any, to complete 103 | // authentication. 104 | 105 | // the api doesn't accept this field back 106 | delete userAttributes.email_verified; 107 | cognitoUser.completeNewPasswordChallenge(newPasswordUser.password, requiredAttributes, { 108 | onSuccess: function (result) { 109 | callback.cognitoCallback(null, userAttributes); 110 | }, 111 | onFailure: function (err) { 112 | callback.cognitoCallback(err, null); 113 | } 114 | }); 115 | }, 116 | onSuccess: function (result) { 117 | callback.cognitoCallback(null, result); 118 | }, 119 | onFailure: function (err) { 120 | callback.cognitoCallback(err, null); 121 | } 122 | }); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/app/shared/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/app/shared/index.ts -------------------------------------------------------------------------------- /src/app/template/app.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /src/assets/css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.6.3 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.6.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.6.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.6.3') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.6.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.6.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.6.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto} 5 | -------------------------------------------------------------------------------- /src/assets/css/login-form.css: -------------------------------------------------------------------------------- 1 | .form-signin { 2 | max-width: 330px; 3 | padding: 15px; 4 | margin: 0 auto; 5 | background-color: white; 6 | } 7 | 8 | .form-signin .form-signin-heading, 9 | .form-signin .checkbox { 10 | margin-bottom: 10px; 11 | } 12 | 13 | .form-signin .checkbox { 14 | font-weight: normal; 15 | } 16 | 17 | .form-signin .form-control { 18 | position: relative; 19 | height: auto; 20 | -webkit-box-sizing: border-box; 21 | -moz-box-sizing: border-box; 22 | box-sizing: border-box; 23 | padding: 10px; 24 | font-size: 16px; 25 | } 26 | 27 | .form-signin .form-control:focus { 28 | z-index: 2; 29 | } 30 | 31 | .form-signin input[type="email"] { 32 | margin-bottom: -1px; 33 | border-bottom-right-radius: 0; 34 | border-bottom-left-radius: 0; 35 | } 36 | 37 | .form-signin input[type="password"] { 38 | margin-bottom: 10px; 39 | border-top-left-radius: 0; 40 | border-top-right-radius: 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/assets/css/sb-admin-2.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2) 3 | * Copyright 2013-2016 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) 5 | */.chat,.timeline{list-style:none}body{background-color:#f8f8f8}#wrapper{width:100%}#page-wrapper{padding:0 15px;min-height:568px;background-color:#fff}@media (min-width:768px){#page-wrapper{position:inherit;margin:0 0 0 250px;padding:0 30px;border-left:1px solid #e7e7e7}}.navbar-top-links{margin-right:0}.navbar-top-links li{display:inline-block}.flot-chart,.navbar-top-links .dropdown-menu li{display:block}.navbar-top-links li:last-child{margin-right:15px}.navbar-top-links li a{padding:15px;min-height:50px}.navbar-top-links .dropdown-menu li:last-child{margin-right:0}.navbar-top-links .dropdown-menu li a{padding:3px 20px;min-height:0}.navbar-top-links .dropdown-menu li a div{white-space:normal}.navbar-top-links .dropdown-alerts,.navbar-top-links .dropdown-messages,.navbar-top-links .dropdown-tasks{width:310px;min-width:0}.navbar-top-links .dropdown-messages{margin-left:5px}.navbar-top-links .dropdown-tasks{margin-left:-59px}.navbar-top-links .dropdown-alerts{margin-left:-123px}.navbar-top-links .dropdown-user{right:0;left:auto}.sidebar .sidebar-nav.navbar-collapse{padding-left:0;padding-right:0}.sidebar .sidebar-search{padding:15px}.sidebar ul li{border-bottom:1px solid #e7e7e7}.sidebar ul li a.active{background-color:#eee}.sidebar .arrow{float:right}.sidebar .fa.arrow:before{content:"\f104"}.sidebar .active>a>.fa.arrow:before{content:"\f107"}.sidebar .nav-second-level li,.sidebar .nav-third-level li{border-bottom:none!important}.sidebar .nav-second-level li a{padding-left:37px}.sidebar .nav-third-level li a{padding-left:52px}@media (min-width:768px){.sidebar{z-index:1;position:absolute;width:250px;margin-top:51px}.navbar-top-links .dropdown-alerts,.navbar-top-links .dropdown-messages,.navbar-top-links .dropdown-tasks{margin-left:auto}}.btn-outline{color:inherit;background-color:transparent;transition:all .5s}.btn-primary.btn-outline{color:#428bca}.btn-success.btn-outline{color:#5cb85c}.btn-info.btn-outline{color:#5bc0de}.btn-warning.btn-outline{color:#f0ad4e}.btn-danger.btn-outline{color:#d9534f}.btn-danger.btn-outline:hover,.btn-info.btn-outline:hover,.btn-primary.btn-outline:hover,.btn-success.btn-outline:hover,.btn-warning.btn-outline:hover{color:#fff}.chat{margin:0;padding:0}.chat li{margin-bottom:10px;padding-bottom:5px;border-bottom:1px dotted #999}.chat li.left .chat-body{margin-left:60px}.chat li.right .chat-body{margin-right:60px}.chat li .chat-body p{margin:0}.chat .glyphicon,.panel .slidedown .glyphicon{margin-right:5px}.chat-panel .panel-body{height:350px;overflow-y:scroll}.login-panel{margin-top:25%}.flot-chart{height:400px}.flot-chart-content{width:100%;height:100%}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{background:0 0}table.dataTable thead .sorting_asc:after{content:"\f0de";float:right;font-family:fontawesome}table.dataTable thead .sorting_desc:after{content:"\f0dd";float:right;font-family:fontawesome}table.dataTable thead .sorting:after{content:"\f0dc";float:right;font-family:fontawesome;color:rgba(50,50,50,.5)}.btn-circle{width:30px;height:30px;padding:6px 0;border-radius:15px;text-align:center;font-size:12px;line-height:1.428571429}.btn-circle.btn-lg{width:50px;height:50px;padding:10px 16px;border-radius:25px;font-size:18px;line-height:1.33}.btn-circle.btn-xl{width:70px;height:70px;padding:10px 16px;border-radius:35px;font-size:24px;line-height:1.33}.show-grid [class^=col-]{padding-top:10px;padding-bottom:10px;border:1px solid #ddd;background-color:#eee!important}.show-grid{margin:15px 0}.huge{font-size:40px}.panel-green{border-color:#5cb85c}.panel-green>.panel-heading{border-color:#5cb85c;color:#fff;background-color:#5cb85c}.panel-green>a{color:#5cb85c}.panel-green>a:hover{color:#3d8b3d}.panel-red{border-color:#d9534f}.panel-red>.panel-heading{border-color:#d9534f;color:#fff;background-color:#d9534f}.panel-red>a{color:#d9534f}.panel-red>a:hover{color:#b52b27}.panel-yellow{border-color:#f0ad4e}.panel-yellow>.panel-heading{border-color:#f0ad4e;color:#fff;background-color:#f0ad4e}.panel-yellow>a{color:#f0ad4e}.panel-yellow>a:hover{color:#df8a13}.timeline{position:relative;padding:20px 0}.timeline:before{content:" ";position:absolute;top:0;bottom:0;left:50%;width:3px;margin-left:-1.5px;background-color:#eee}.timeline>li{position:relative;margin-bottom:20px}.timeline>li:after,.timeline>li:before{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-panel{float:left;position:relative;width:46%;padding:20px;border:1px solid #d4d4d4;border-radius:2px;-webkit-box-shadow:0 1px 6px rgba(0,0,0,.175);box-shadow:0 1px 6px rgba(0,0,0,.175)}.timeline>li>.timeline-panel:before{content:" ";display:inline-block;position:absolute;top:26px;right:-15px;border-top:15px solid transparent;border-right:0 solid #ccc;border-bottom:15px solid transparent;border-left:15px solid #ccc}.timeline>li>.timeline-panel:after{content:" ";display:inline-block;position:absolute;top:27px;right:-14px;border-top:14px solid transparent;border-right:0 solid #fff;border-bottom:14px solid transparent;border-left:14px solid #fff}.timeline>li>.timeline-badge{z-index:100;position:absolute;top:16px;left:50%;width:50px;height:50px;margin-left:-25px;border-radius:50%;text-align:center;font-size:1.4em;line-height:50px;color:#fff;background-color:#999}.timeline>li.timeline-inverted>.timeline-panel{float:right}.timeline>li.timeline-inverted>.timeline-panel:before{right:auto;left:-15px;border-right-width:15px;border-left-width:0}.timeline>li.timeline-inverted>.timeline-panel:after{right:auto;left:-14px;border-right-width:14px;border-left-width:0}.timeline-badge.primary{background-color:#2e6da4!important}.timeline-badge.success{background-color:#3f903f!important}.timeline-badge.warning{background-color:#f0ad4e!important}.timeline-badge.danger{background-color:#d9534f!important}.timeline-badge.info{background-color:#5bc0de!important}.timeline-title{margin-top:0;color:inherit}.timeline-body>p,.timeline-body>ul{margin-bottom:0}.timeline-body>p+p{margin-top:5px}@media (max-width:767px){ul.timeline:before{left:40px}ul.timeline>li>.timeline-panel{width:calc(10%);width:-moz-calc(10%);width:-webkit-calc(10%);float:right}ul.timeline>li>.timeline-badge{top:16px;left:15px;margin-left:0}ul.timeline>li>.timeline-panel:before{right:auto;left:-15px;border-right-width:15px;border-left-width:0}ul.timeline>li>.timeline-panel:after{right:auto;left:-14px;border-right-width:14px;border-left-width:0}} -------------------------------------------------------------------------------- /src/assets/css/starter.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Start Bootstrap - Landing Page (http://startbootstrap.com/) 3 | * Copyright 2013-2016 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) 5 | */ 6 | 7 | body, 8 | html { 9 | width: 100%; 10 | height: 100%; 11 | 12 | background: url(../img/intro-bg.jpg) no-repeat center center; 13 | background-size: cover; 14 | } 15 | 16 | body, 17 | h1, 18 | h2, 19 | h3, 20 | h4, 21 | h5, 22 | h6 { 23 | font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif; 24 | font-weight: 700; 25 | } 26 | 27 | .topnav { 28 | font-size: 14px; 29 | } 30 | 31 | .lead { 32 | font-size: 18px; 33 | font-weight: 400; 34 | } 35 | 36 | .intro-header { 37 | padding-top: 50px; /* If you're making other pages, make sure there is 50px of padding to make sure the navbar doesn't overlap content! */ 38 | padding-bottom: 50px; 39 | text-align: center; 40 | color: #0d6aad; 41 | /*background: url(../img/intro-bg.jpg) no-repeat center center;*/ 42 | /*background-size: cover;*/ 43 | } 44 | 45 | .intro-message { 46 | position: relative; 47 | padding-top: 20%; 48 | padding-bottom: 20%; 49 | } 50 | 51 | .intro-message > h1 { 52 | margin: 0; 53 | text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.6); 54 | font-size: 5em; 55 | } 56 | 57 | .intro-divider { 58 | width: 400px; 59 | border-top: 1px solid #f8f8f8; 60 | border-bottom: 1px solid rgba(0, 0, 0, 0.2); 61 | } 62 | 63 | .intro-message > h3 { 64 | text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.6); 65 | } 66 | 67 | @media (max-width: 767px) { 68 | .intro-message { 69 | padding-bottom: 15%; 70 | } 71 | 72 | .intro-message > h1 { 73 | font-size: 3em; 74 | } 75 | 76 | ul.intro-social-buttons > li { 77 | display: block; 78 | margin-bottom: 20px; 79 | padding: 0; 80 | } 81 | 82 | ul.intro-social-buttons > li:last-child { 83 | margin-bottom: 0; 84 | } 85 | 86 | .intro-divider { 87 | width: 100%; 88 | } 89 | } 90 | 91 | .network-name { 92 | text-transform: uppercase; 93 | font-size: 14px; 94 | font-weight: 400; 95 | letter-spacing: 2px; 96 | } 97 | 98 | .content-section-a { 99 | padding: 50px 0; 100 | background-color: #f8f8f8; 101 | } 102 | 103 | .content-section-b { 104 | padding: 50px 0; 105 | border-top: 1px solid #e7e7e7; 106 | border-bottom: 1px solid #e7e7e7; 107 | } 108 | 109 | .section-heading { 110 | margin-bottom: 30px; 111 | } 112 | 113 | .section-heading-spacer { 114 | float: left; 115 | width: 200px; 116 | border-top: 3px solid #e7e7e7; 117 | } 118 | 119 | .banner { 120 | padding: 100px 0; 121 | color: #f8f8f8; 122 | background: url(../img/banner-bg.jpg) no-repeat center center; 123 | background-size: cover; 124 | } 125 | 126 | .banner h2 { 127 | margin: 0; 128 | text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.6); 129 | font-size: 3em; 130 | } 131 | 132 | .banner ul { 133 | margin-bottom: 0; 134 | } 135 | 136 | .banner-social-buttons { 137 | float: right; 138 | margin-top: 0; 139 | } 140 | 141 | @media (max-width: 1199px) { 142 | ul.banner-social-buttons { 143 | float: left; 144 | margin-top: 15px; 145 | } 146 | } 147 | 148 | @media (max-width: 767px) { 149 | .banner h2 { 150 | margin: 0; 151 | text-shadow: 2px 2px 3px rgba(0, 0, 0, 0.6); 152 | font-size: 3em; 153 | } 154 | 155 | ul.banner-social-buttons > li { 156 | display: block; 157 | margin-bottom: 20px; 158 | padding: 0; 159 | } 160 | 161 | ul.banner-social-buttons > li:last-child { 162 | margin-bottom: 0; 163 | } 164 | } 165 | 166 | footer { 167 | padding: 50px 0; 168 | background-color: #f8f8f8; 169 | } 170 | 171 | p.copyright { 172 | margin: 15px 0 0; 173 | } 174 | -------------------------------------------------------------------------------- /src/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/assets/img/intro-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/assets/img/intro-bg.jpg -------------------------------------------------------------------------------- /src/assets/ui-js/metisMenu.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * metismenu - v1.1.3 3 | * Easy menu jQuery plugin for Twitter Bootstrap 3 4 | * https://github.com/onokumus/metisMenu 5 | * 6 | * Made by Osman Nuri Okumus 7 | * Under MIT License 8 | */ 9 | !function(a,b,c){function d(b,c){this.element=a(b),this.settings=a.extend({},f,c),this._defaults=f,this._name=e,this.init()}var e="metisMenu",f={toggle:!0,doubleTapToGo:!1};d.prototype={init:function(){var b=this.element,d=this.settings.toggle,f=this;this.isIE()<=9?(b.find("li.active").has("ul").children("ul").collapse("show"),b.find("li").not(".active").has("ul").children("ul").collapse("hide")):(b.find("li.active").has("ul").children("ul").addClass("collapse in"),b.find("li").not(".active").has("ul").children("ul").addClass("collapse")),f.settings.doubleTapToGo&&b.find("li.active").has("ul").children("a").addClass("doubleTapToGo"),b.find("li").has("ul").children("a").on("click."+e,function(b){return b.preventDefault(),f.settings.doubleTapToGo&&f.doubleTapToGo(a(this))&&"#"!==a(this).attr("href")&&""!==a(this).attr("href")?(b.stopPropagation(),void(c.location=a(this).attr("href"))):(a(this).parent("li").toggleClass("active").children("ul").collapse("toggle"),void(d&&a(this).parent("li").siblings().removeClass("active").children("ul.in").collapse("hide")))})},isIE:function(){for(var a,b=3,d=c.createElement("div"),e=d.getElementsByTagName("i");d.innerHTML="",e[0];)return b>4?b:a},doubleTapToGo:function(a){var b=this.element;return a.hasClass("doubleTapToGo")?(a.removeClass("doubleTapToGo"),!0):a.parent().children("ul").length?(b.find(".doubleTapToGo").removeClass("doubleTapToGo"),a.addClass("doubleTapToGo"),!1):void 0},remove:function(){this.element.off("."+e),this.element.removeData(e)}},a.fn[e]=function(b){return this.each(function(){var c=a(this);c.data(e)&&c.data(e).remove(),c.data(e,new d(this,b))}),this}}(jQuery,window,document); -------------------------------------------------------------------------------- /src/assets/ui-js/sb-admin-2.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Start Bootstrap - SB Admin 2 v3.3.7+1 (http://startbootstrap.com/template-overviews/sb-admin-2) 3 | * Copyright 2013-2016 Start Bootstrap 4 | * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) 5 | */ 6 | $(function(){$("#side-menu").metisMenu()}),$(function(){$(window).bind("load resize",function(){var i=50,n=this.window.innerWidth>0?this.window.innerWidth:this.screen.width;n<768?($("div.navbar-collapse").addClass("collapse"),i=100):$("div.navbar-collapse").removeClass("collapse");var e=(this.window.innerHeight>0?this.window.innerHeight:this.screen.height)-1;e-=i,e<1&&(e=1),e>i&&$("#page-wrapper").css("min-height",e+"px")});for(var i=window.location,n=$("ul.nav a").filter(function(){return this.href==i}).addClass("active").parent();;){if(!n.is("li"))break;n=n.parent().addClass("in").parent()}}); -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true, 3 | 4 | region: 'us-east-1', 5 | 6 | identityPoolId: 'us-east-1:fbe0340f-9ffc-4449-a935-bb6a6661fd53', 7 | userPoolId: 'us-east-1_PGSbCVZ7S', 8 | clientId: 'hh5ibv67so0qukt55c5ulaltk', 9 | 10 | rekognitionBucket: 'rekognition-pics', 11 | albumName: "usercontent", 12 | bucketRegion: 'us-east-1', 13 | 14 | ddbTableName: 'LoginTrail', 15 | 16 | cognito_idp_endpoint: '', 17 | cognito_identity_endpoint: '', 18 | sts_endpoint: '', 19 | dynamodb_endpoint: '', 20 | s3_endpoint: '' 21 | 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: false, 3 | 4 | region: 'us-east-1', 5 | 6 | identityPoolId: 'us-east-1:fbe0340f-9ffc-4449-a935-bb6a6661fd53', 7 | userPoolId: 'us-east-1_PGSbCVZ7S', 8 | clientId: 'hh5ibv67so0qukt55c5ulaltk', 9 | 10 | rekognitionBucket: 'rekognition-pics', 11 | albumName: "usercontent", 12 | bucketRegion: 'us-east-1', 13 | 14 | ddbTableName: 'LoginTrail', 15 | 16 | cognito_idp_endpoint: '', 17 | cognito_identity_endpoint: '', 18 | sts_endpoint: '', 19 | dynamodb_endpoint: '', 20 | s3_endpoint: '' 21 | 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amazon-archives/aws-cognito-angular-quickstart/79c29ec50ba920ee20de7bec7cd2d4aa451039ba/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AWS Cognito User Pools QuickStart 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Loading... 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import "./polyfills.ts"; 2 | import {platformBrowserDynamic} from "@angular/platform-browser-dynamic"; 3 | import {enableProdMode} from "@angular/core"; 4 | import {environment} from "./environments/environment"; 5 | import {AppModule} from "./app/"; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | import "core-js/es6/symbol"; 2 | import "core-js/es6/object"; 3 | import "core-js/es6/function"; 4 | import "core-js/es6/parse-int"; 5 | import "core-js/es6/parse-float"; 6 | import "core-js/es6/number"; 7 | import "core-js/es6/math"; 8 | import "core-js/es6/string"; 9 | import "core-js/es6/date"; 10 | import "core-js/es6/array"; 11 | import "core-js/es6/regexp"; 12 | import "core-js/es6/map"; 13 | import "core-js/es6/set"; 14 | import "core-js/es6/reflect"; 15 | import "core-js/es7/reflect"; 16 | import "zone.js/dist/zone"; -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "lib": [ 9 | "es2016", 10 | "dom" 11 | ], 12 | "outDir": "../out-tsc/app", 13 | "target": "es5", 14 | "module": "es2015", 15 | "baseUrl": "" 16 | }, 17 | "exclude": [ 18 | "test.ts", 19 | "**/*.spec.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "lib": [ 9 | "es2016" 10 | ], 11 | "outDir": "../out-tsc/spec", 12 | "module": "commonjs", 13 | "target": "es6", 14 | "baseUrl": "", 15 | "types": [ 16 | "jasmine", 17 | "node" 18 | ] 19 | }, 20 | "files": [ 21 | "test.ts" 22 | ], 23 | "include": [ 24 | "**/*.spec.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | // Typings reference file, see links for more information 2 | // https://github.com/typings/typings 3 | // https://www.typescriptlang.org/docs/handbook/writing-declaration-files.html 4 | 5 | declare var System: any; 6 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "class-name": true, 7 | "comment-format": [ 8 | true, 9 | "check-space" 10 | ], 11 | "curly": true, 12 | "eofline": true, 13 | "forin": true, 14 | "indent": [ 15 | true, 16 | "spaces" 17 | ], 18 | "label-position": true, 19 | "label-undefined": true, 20 | "max-line-length": [ 21 | true, 22 | 140 23 | ], 24 | "member-access": false, 25 | "member-ordering": [ 26 | true, 27 | "static-before-instance", 28 | "variables-before-functions" 29 | ], 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-console": [ 33 | true, 34 | "debug", 35 | "info", 36 | "time", 37 | "timeEnd", 38 | "trace" 39 | ], 40 | "no-construct": true, 41 | "no-debugger": true, 42 | "no-duplicate-key": true, 43 | "no-duplicate-variable": true, 44 | "no-empty": false, 45 | "no-eval": true, 46 | "no-inferrable-types": true, 47 | "no-shadowed-variable": true, 48 | "no-string-literal": false, 49 | "no-switch-case-fall-through": true, 50 | "no-trailing-whitespace": true, 51 | "no-unused-expression": true, 52 | "no-unused-variable": true, 53 | "no-unreachable": true, 54 | "no-use-before-declare": true, 55 | "no-var-keyword": true, 56 | "object-literal-sort-keys": false, 57 | "one-line": [ 58 | true, 59 | "check-open-brace", 60 | "check-catch", 61 | "check-else", 62 | "check-whitespace" 63 | ], 64 | "quotemark": [ 65 | true, 66 | "single" 67 | ], 68 | "radix": true, 69 | "semicolon": [ 70 | "always" 71 | ], 72 | "triple-equals": [ 73 | true, 74 | "allow-null-check" 75 | ], 76 | "typedef-whitespace": [ 77 | true, 78 | { 79 | "call-signature": "nospace", 80 | "index-signature": "nospace", 81 | "parameter": "nospace", 82 | "property-declaration": "nospace", 83 | "variable-declaration": "nospace" 84 | } 85 | ], 86 | "variable-name": false, 87 | "whitespace": [ 88 | true, 89 | "check-branch", 90 | "check-decl", 91 | "check-operator", 92 | "check-separator", 93 | "check-type" 94 | ], 95 | 96 | "directive-selector-prefix": [true, "app"], 97 | "component-selector-prefix": [true, "app"], 98 | "directive-selector-name": [true, "camelCase"], 99 | "component-selector-name": [true, "kebab-case"], 100 | "directive-selector-type": [true, "attribute"], 101 | "component-selector-type": [true, "element"], 102 | "use-input-property-decorator": true, 103 | "use-output-property-decorator": true, 104 | "use-host-property-decorator": true, 105 | "no-input-rename": true, 106 | "no-output-rename": true, 107 | "use-life-cycle-interface": true, 108 | "use-pipe-transform-interface": true, 109 | "component-class-suffix": true, 110 | "directive-class-suffix": true 111 | } 112 | } 113 | --------------------------------------------------------------------------------