import { Injectable } from '@angular/core' ; import { Http , Headers } from '@angular/http' ; import { Config } from '../config/config' ; import { Logger } from './logger.service' ; import * as sjcl from '../assets/vendor/sjcl' ; declare const AWS ; declare const AWSCognito ; export enum UserState { SignedOut = 0 , SignedIn = 1 , PendingConfirmation = 2 , InvalidCredentials = 3 } export interface IUserRegistration { email ? : string ; givenName ? : string ; familyName ? : string ; username ? : string ; password ? : string ; } export interface IUserLogin { username ? : string ; password ? : string ; } interface IUserAttribute { Name : string ; Value : string ; } @ Injectable ( ) export class CognitoUtil { private static _USER_POOL_ID = Config [ 'USER_POOL_ID' ] ; private static _USER_POOL_DOMAIN_NAME = Config [ 'USER_POOL_DOMAIN_NAME' ] ; private static _CLIENT_ID : string = Config [ 'CLIENT_ID' ] ; private static _IDENTITY_POOL_ID : string = Config [ 'IDENTITY_POOL_ID' ] ; private static _REGION : string = Config [ 'REGION' ] ; private static _MOBILE_REDIRECT_URI = 'spacefinder://callback' ; private static _WEB_REDIRECT_URI = 'http://localhost:8100' ; private static _RESPONSE_TYPE = 'code' ; public static getRegion ( ) { return CognitoUtil . _REGION ; } public static getHostedUiLoginMobileUrl ( ) { return 'https://' + CognitoUtil . _USER_POOL_DOMAIN_NAME + '/login?redirect_uri=' + CognitoUtil . _MOBILE_REDIRECT_URI + '&response_type=' + CognitoUtil . _RESPONSE_TYPE + '&client_id=' + CognitoUtil . _CLIENT_ID ; } public static getHostedUiLoginWebUrl ( ) { return 'https://' + CognitoUtil . _USER_POOL_DOMAIN_NAME + '/login?redirect_uri=' + CognitoUtil . _WEB_REDIRECT_URI + '&response_type=' + CognitoUtil . _RESPONSE_TYPE + '&client_id=' + CognitoUtil . _CLIENT_ID ; } private static getHostedUiTokenUrl ( ) { return 'https://' + CognitoUtil . _USER_POOL_DOMAIN_NAME + '/oauth2/token' ; } public static getIdTokenFromAuthCode ( authCode , platform , http ) { return new Promise ( ( resolve , reject ) => { let headers = new Headers ( ) ; let requestRedirectUri ; switch ( platform ) { case 'mobile' : requestRedirectUri = CognitoUtil . _MOBILE_REDIRECT_URI ; break ; case 'web' : requestRedirectUri = CognitoUtil . _WEB_REDIRECT_URI ; break ; } headers . append ( 'Content-Type' , 'application/x-www-form-urlencoded' ) ; let body = 'grant_type=authorization_code&' + 'client_id=' + CognitoUtil . _CLIENT_ID + '&' + 'redirect_uri=' + requestRedirectUri + '&' + 'code=' + authCode ; http . post ( CognitoUtil . getHostedUiTokenUrl ( ) , body , { headers : headers } ) . map ( res => res . json ( ) ) . subscribe ( data => { resolve ( data ) ; } ) ; } ) ; } public static getClientId ( ) { return CognitoUtil . _CLIENT_ID ; } public static getIdentityPoolId ( ) { return CognitoUtil . _IDENTITY_POOL_ID ; } public static getUserPoolId ( ) { return CognitoUtil . _USER_POOL_ID ; } public static getCognitoIdentityId ( ) { return AWS . config . credentials . identityId ; } public static getUsername ( ) { return LocalStorage . get ( 'userName' ) ; } public static setUsername ( username ) { LocalStorage . set ( 'userName' , username ) ; } public static getUserId ( ) { return LocalStorage . get ( 'userId' ) ; } public static getUserProfile ( ) { return LocalStorage . getObject ( 'userProfile' ) ; } public static getUserGroup ( ) { return LocalStorage . get ( "userGroup" ) ; } public static getUserState ( ) { switch ( parseInt ( LocalStorage . get ( 'userState' ) ) ) { case 0 : return UserState . SignedOut ; case 1 : return UserState . SignedIn ; case 2 : return UserState . PendingConfirmation ; case 3 : return UserState . InvalidCredentials ; default : return null ; } } ; public static setUserState ( userState ) { LocalStorage . set ( 'userState' , JSON . stringify ( userState ) ) ; } public static getUserPool ( ) { let poolData = { UserPoolId : CognitoUtil . _USER_POOL_ID , ClientId : CognitoUtil . _CLIENT_ID } ; AWSCognito . config . region = CognitoUtil . _REGION ; AWSCognito . config . credentials = new AWS . CognitoIdentityCredentials ( { IdentityPoolId : CognitoUtil . _IDENTITY_POOL_ID } ) ; AWSCognito . config . update ( { accessKeyId : 'dummyvalue' , secretAccessKey : 'dummyvalue' } ) ; return new AWSCognito . CognitoIdentityServiceProvider . CognitoUserPool ( poolData ) ; } public static getCognitoUser ( ) { let username = LocalStorage . get ( 'userName' ) ; let userData = { Username : username , Pool : CognitoUtil . getUserPool ( ) } ; return new AWSCognito . CognitoIdentityServiceProvider . CognitoUser ( userData ) ; } public static getCurrentUser ( ) { return CognitoUtil . getUserPool ( ) . getCurrentUser ( ) ; } } @ Injectable ( ) export class UserRegistrationService { public static signUp ( signUpData ) { let attributeList = [ ] ; let dataEmail = { Name : 'email' , Value : signUpData . email } ; let dataGivenName = { Name : 'given_name' , Value : signUpData . givenName } ; let dataFamilyName = { Name : 'family_name' , Value : signUpData . familyName } ; let attributeEmail = new AWSCognito . CognitoIdentityServiceProvider . CognitoUserAttribute ( dataEmail ) ; let attributeGivenName = new AWSCognito . CognitoIdentityServiceProvider . CognitoUserAttribute ( dataGivenName ) ; let attributeFamilyName = new AWSCognito . CognitoIdentityServiceProvider . CognitoUserAttribute ( dataFamilyName ) ; attributeList . push ( attributeEmail ) ; attributeList . push ( attributeGivenName ) ; attributeList . push ( attributeFamilyName ) ; let promise = new Promise < void > ( ( resolve , reject ) => { CognitoUtil . getUserPool ( ) . signUp ( signUpData . username , signUpData . password , attributeList , undefined , ( err , result ) => { if ( err ) { reject ( err ) ; return ; } console . log ( 'Username is ' + result . user . getUsername ( ) ) ; console . log ( 'Sign-up successful!' ) ; CognitoUtil . setUsername ( signUpData . username ) ; CognitoUtil . setUserState ( UserState . PendingConfirmation ) ; resolve ( ) ; } ) ; } ) ; return promise ; } public static confirmSignUp ( confirmationCode ) { let cognitoUser = CognitoUtil . getCognitoUser ( ) ; let promise = new Promise < void > ( ( resolve , reject ) => { cognitoUser . confirmRegistration ( confirmationCode , true , ( err , data ) => { if ( err ) { reject ( err ) ; return ; } CognitoUtil . setUserState ( UserState . SignedIn ) ; resolve ( data ) ; } ) ; } ) ; return promise ; } public static resendConfirmationCode ( ) { let cognitoParams = { ClientId : CognitoUtil . getClientId ( ) , Username : CognitoUtil . getUsername ( ) } ; let promise = new Promise < void > ( ( resolve , reject ) => { new AWSCognito . CognitoIdentityServiceProvider ( ) . resendConfirmationCode ( cognitoParams , ( err , data ) => { if ( err ) { reject ( err ) ; return ; } resolve ( data ) ; } ) ; } ) ; return promise ; } } @ Injectable ( ) export class UserLoginService { private static _userTokens = { accessToken : undefined , idToken : undefined , refreshToken : undefined } ; public static getAccessToken ( ) { let accessToken = UserLoginService . _userTokens . accessToken ; if ( ! accessToken ) { accessToken = LocalStorage . get ( 'userTokens.accessToken' ) ; UserLoginService . _userTokens . accessToken = accessToken ; } return accessToken ; } ; public static getIdToken ( ) { let idToken = UserLoginService . _userTokens . idToken ; if ( ! idToken ) { idToken = LocalStorage . get ( 'userTokens.idToken' ) ; UserLoginService . _userTokens . idToken = idToken ; } return idToken ; } ; public static getRefreshToken ( ) { let refreshToken = UserLoginService . _userTokens . refreshToken ; if ( ! refreshToken ) { refreshToken = LocalStorage . get ( 'userTokens.refreshToken' ) ; UserLoginService . _userTokens . refreshToken = refreshToken ; } return refreshToken ; } public static getAwsAccessKey ( ) { if ( AWS . config . credentials == null ) { return LocalStorage . get ( 'userTokens.awsAccessKeyId' ) ; } return AWS . config . credentials . accessKeyId || LocalStorage . get ( 'userTokens.awsAccessKeyId' ) ; } public static getAwsSecretAccessKey ( ) { return AWS . config . credentials . secretAccessKey || LocalStorage . get ( 'userTokens.awsSecretAccessKey' ) ; } public static getAwsSessionToken ( ) { return AWS . config . credentials . sessionToken || LocalStorage . get ( 'userTokens.awsSessionToken' ) ; } private static clearUserState ( ) { UserLoginService . _userTokens = { accessToken : undefined , idToken : undefined , refreshToken : undefined } ; LocalStorage . set ( 'userTokens.accessToken' , null ) ; LocalStorage . set ( 'userTokens.idToken' , null ) ; LocalStorage . set ( 'userTokens.refreshToken' , null ) ; LocalStorage . set ( 'userTokens.awsAccessKeyId' , null ) ; LocalStorage . set ( 'userTokens.awsSecretAccessKey' , null ) ; LocalStorage . set ( 'userTokens.awsSessionToken' , null ) ; CognitoUtil . setUserState ( UserState . SignedOut ) ; LocalStorage . set ( 'userProfile' , null ) ; LocalStorage . set ( 'userId' , null ) ; LocalStorage . set ( 'userName' , null ) ; } ; public static signIn ( userLogin ) { let authenticationData = { Username : userLogin . username , Password : userLogin . password } ; let authenticationDetails = new AWSCognito . CognitoIdentityServiceProvider . AuthenticationDetails ( authenticationData ) ; CognitoUtil . setUsername ( userLogin . username ) ; console . log ( 'Authenticating user ' + userLogin . username ) ; let cognitoUser = CognitoUtil . getCognitoUser ( ) ; let promise = new Promise < void > ( ( resolve , reject ) => { cognitoUser . authenticateUser ( authenticationDetails , { onSuccess : function ( result ) { console . log ( result ) ; UserLoginService . completeSignIn ( result . getAccessToken ( ) . getJwtToken ( ) , result . getIdToken ( ) . getJwtToken ( ) , result . getRefreshToken ( ) . getToken ( ) ) . then ( ( ) => { resolve ( ) ; } ) . catch ( ( err ) => { reject ( err ) ; } ) ; } , onFailure : function ( err ) { if ( err . code === 'UserNotConfirmedException' ) { CognitoUtil . setUserState ( UserState . PendingConfirmation ) ; } else { CognitoUtil . setUserState ( UserState . InvalidCredentials ) ; } reject ( err ) ; } } ) ; } ) ; return promise ; } public static completeSignIn ( accessToken , idToken , refreshToken ) { let promise = new Promise < void > ( ( resolve , reject ) => { UserLoginService . _userTokens . accessToken = accessToken ; UserLoginService . _userTokens . idToken = idToken ; UserLoginService . _userTokens . refreshToken = refreshToken ; LocalStorage . set ( 'userTokens.idToken' , UserLoginService . _userTokens . idToken ) ; console . log ( '%cCognito User Pools Identity Token: ' , Logger . LeadInStyle , UserLoginService . getIdToken ( ) ) ; LocalStorage . set ( 'userTokens.accessToken' , UserLoginService . _userTokens . accessToken ) ; console . log ( '%cCognito User Pools Access Token: ' , Logger . LeadInStyle , UserLoginService . getAccessToken ( ) ) ; LocalStorage . set ( 'userTokens.refreshToken' , UserLoginService . _userTokens . refreshToken ) ; console . log ( '%cCognito User Pools Refresh Token: ' , Logger . LeadInStyle , UserLoginService . getRefreshToken ( ) ) ; let idTokenPayload = UserLoginService . _userTokens . idToken . split ( '.' ) [ 1 ] ; let idTokenDecoded = JSON . parse ( sjcl . codec . utf8String . fromBits ( sjcl . codec . base64url . toBits ( idTokenPayload ) ) ) ; CognitoUtil . setUsername ( idTokenDecoded [ "cognito:username" ] ) ; let userName = idTokenDecoded [ "cognito:username" ] ; let userGroup = idTokenDecoded [ "cognito:groups" ] ; if ( userGroup && userGroup . length > 0 ) { LocalStorage . set ( 'userGroup' , userGroup ) ; } else { userGroup = 'clientGroup' ; LocalStorage . set ( 'userGroup' , userGroup [ 0 ] ) ; } console . log ( '%cCognito User Pools User Groups: ' + '%c%s belongs to group %s' , Logger . LeadInStyle , "black" , userName , userGroup [ 0 ] ) ; CognitoUtil . setUserState ( UserState . SignedIn ) ; console . log ( '%cCognito User Pools User Attributes: ' , Logger . LeadInStyle , idTokenDecoded ) ; LocalStorage . setObject ( 'userProfile' , idTokenDecoded ) ; UserLoginService . getAwsCredentials ( ) . then ( ( ) => { LocalStorage . set ( 'userId' , CognitoUtil . getCognitoIdentityId ( ) ) ; console . log ( '%cCognito Identity ID: ' , Logger . LeadInStyle , CognitoUtil . getCognitoIdentityId ( ) ) ; LocalStorage . set ( 'userTokens.awsAccessKeyId' , AWS . config . credentials . accessKeyId ) ; console . log ( '%cAWS Access Key ID: ' , Logger . LeadInStyle , AWS . config . credentials . accessKeyId ) ; LocalStorage . set ( 'userTokens.awsSecretAccessKey' , AWS . config . credentials . secretAccessKey ) ; console . log ( '%cAWS Secret Access Key: ' , Logger . LeadInStyle , AWS . config . credentials . secretAccessKey ) ; LocalStorage . set ( 'userTokens.awsSessionToken' , AWS . config . credentials . sessionToken ) ; console . log ( '%cAWS Session Token: ' , Logger . LeadInStyle , AWS . config . credentials . sessionToken ) ; resolve ( ) ; } ) . catch ( ( err ) => { reject ( err ) ; } ) ; } ) ; return promise ; } public static signOut ( ) { UserLoginService . clearUserState ( ) ; CognitoUtil . getCognitoUser ( ) . signOut ( ) ; AWS . config . credentials . clearCachedId ( ) ; } public static globalSignOut ( ) { UserLoginService . clearUserState ( ) ; CognitoUtil . getCognitoUser ( ) . globalSignOut ( ) ; AWS . config . credentials . clearCachedId ( ) ; } public static changePassword ( previousPassword , proposedPassword ) { let promise = new Promise < void > ( ( resolve , reject ) => { let cognitoUser = CognitoUtil . getCognitoUser ( ) ; cognitoUser . getSession ( ( err , session ) => { if ( err ) { reject ( err ) ; return ; } cognitoUser . changePassword ( previousPassword , proposedPassword , ( err , result ) => { if ( err ) { reject ( err ) ; return ; } resolve ( result ) ; } ) ; } ) ; } ) ; return promise ; } public static forgotPassword ( username ) { CognitoUtil . setUsername ( username ) ; let cognitoUser = CognitoUtil . getCognitoUser ( ) ; let promise = new Promise < void > ( ( resolve , reject ) => { cognitoUser . forgotPassword ( { onSuccess : ( result ) => { console . log ( 'Initiated reset password for username ' + username ) ; resolve ( result ) ; } , onFailure : ( err ) => { console . log ( 'Failed to initiate reset password for username ' + username ) ; reject ( err ) ; return ; } } ) ; } ) ; return promise ; } public static confirmForgotPassword ( username , verificationCode , password ) { CognitoUtil . setUsername ( username ) ; let cognitoUser = CognitoUtil . getCognitoUser ( ) ; let promise = new Promise < void > ( ( resolve , reject ) => { cognitoUser . confirmPassword ( verificationCode , password , { onSuccess : ( result ) => { console . log ( 'Password successfully reset for username ' + username ) ; resolve ( result ) ; } , onFailure : ( err ) => { console . log ( 'Password was not reset for username ' + username ) ; console . log ( `Error: ${ err . name }. ${ err . message }` ) ; reject ( err ) ; return ; } } ) ; } ) ; return promise ; } public static getAwsCredentials ( ) { let promise = new Promise < void > ( ( resolve , reject ) => { let logins = { } ; logins [ 'cognito-idp.' + CognitoUtil . getRegion ( ) + '.amazonaws.com/' + CognitoUtil . getUserPoolId ( ) ] = LocalStorage . get ( 'userTokens.idToken' ) ; ; AWS . config . region = CognitoUtil . getRegion ( ) ; AWS . config . credentials = new AWS . CognitoIdentityCredentials ( { IdentityPoolId : CognitoUtil . getIdentityPoolId ( ) } ) ; AWS . config . credentials = new AWS . CognitoIdentityCredentials ( { IdentityPoolId : CognitoUtil . getIdentityPoolId ( ) , Logins : logins } ) ; if ( AWS . config . credentials . needsRefresh ( ) ) { AWS . config . credentials . clearCachedId ( ) ; AWS . config . credentials . get ( ( err ) => { if ( err ) { reject ( err ) ; return ; } resolve ( ) ; } ) ; } else { AWS . config . credentials . get ( ( err ) => { if ( err ) { console . error ( err ) ; reject ( err ) ; return ; } resolve ( ) ; } ) ; } } ) ; return promise ; } } export class UserProfileService { public static getUserAttributes ( ) { let promise = new Promise < Object > ( ( resolve , reject ) => { let cognitoUser = CognitoUtil . getCognitoUser ( ) ; cognitoUser . getSession ( ( err , session ) => { if ( err ) { reject ( err ) ; return ; } cognitoUser . getUserAttributes ( ( err , result ) => { if ( err ) { reject ( err ) ; return ; } let userAttributes = { } ; for ( var i = 0 ; i < result . length ; i ++ ) { userAttributes [ result [ i ] . getName ( ) ] = result [ i ] . getValue ( ) ; } console . log ( '%cCognito User Pools User Attributes: ' , Logger . LeadInStyle , userAttributes ) ; LocalStorage . setObject ( 'userProfile' , userAttributes ) ; resolve ( userAttributes ) ; } ) ; } ) ; } ) ; return promise ; } } @ Injectable ( ) export class LocalStorage { private static getLocalStorage ( ) { let storage = window . localStorage || localStorage ; if ( ! localStorage ) { throw new Error ( 'Browser does not support local storage' ) ; } return storage ; } public static set ( key , value ) { LocalStorage . getLocalStorage ( ) . setItem ( key , value ) ; } public static get ( key ) { return LocalStorage . getLocalStorage ( ) . getItem ( key ) ; } public static setObject ( key , value ) { LocalStorage . set ( key , JSON . stringify ( value ) ) ; } public static getObject ( key ) { return JSON . parse ( LocalStorage . get ( key ) || '{}' ) ; } public static remove ( key ) { LocalStorage . getLocalStorage ( ) . removeItem ( key ) ; } } export const LOCAL_STORAGE_PROVIDERS = [ { provide : LocalStorage , useClass : LocalStorage } ] ;