155 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import { Observable } from 'rx';
 | |
| // import debug from 'debug';
 | |
| import dedent from 'dedent';
 | |
| import { isEmail } from 'validator';
 | |
| 
 | |
| import { observeMethod, observeQuery } from '../../server/utils/rx';
 | |
| import { wrapHandledError } from '../../server/utils/create-handled-error.js';
 | |
| 
 | |
| // const log = debug('fcc:models:userIdent');
 | |
| 
 | |
| export default function(UserIdent) {
 | |
| 
 | |
|   UserIdent.on('dataSourceAttached', () => {
 | |
|     UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
 | |
|   });
 | |
| 
 | |
|   UserIdent.login = function(
 | |
|     _provider,
 | |
|     authScheme,
 | |
|     profile,
 | |
|     credentials,
 | |
|     options,
 | |
|     cb
 | |
|   ) {
 | |
|     const User = UserIdent.app.models.User;
 | |
|     const AccessToken = UserIdent.app.models.AccessToken;
 | |
|     options = options || {};
 | |
|     if (typeof options === 'function' && !cb) {
 | |
|       cb = options;
 | |
|       options = {};
 | |
|     }
 | |
| 
 | |
|     // get the social provider data and the external id from auth0
 | |
|     profile.id = profile.id || profile.openid;
 | |
|     const auth0IdString = '' + profile.id;
 | |
|     const [ provider, socialExtId ] = auth0IdString.split('|');
 | |
|     const query = {
 | |
|       where: {
 | |
|         provider: provider,
 | |
|         externalId: socialExtId
 | |
|       },
 | |
|       include: 'user'
 | |
|     };
 | |
|     // get the email from the auth0 (its expected from social providers)
 | |
|     const email = (profile && profile.emails && profile.emails[0]) ?
 | |
|                     profile.emails[0].value : '';
 | |
|     if (!isEmail('' + email)) {
 | |
|       throw wrapHandledError(
 | |
|         new Error('invalid or empty email recieved from auth0'),
 | |
|         {
 | |
|           message: dedent`
 | |
|     Oops... something is not right. We did not find a valid email from your
 | |
|     ${provider} account. Please try again with a different provider that has an
 | |
|     email available with it.
 | |
|           `,
 | |
|           type: 'info',
 | |
|           redirectTo: '/'
 | |
|         }
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     if (provider === 'email') {
 | |
| 
 | |
|       return User.findOne$({ where: { email } })
 | |
|         .flatMap(user => {
 | |
|           return user ?
 | |
|             Observable.of(user) :
 | |
|             User.create$({ email }).toPromise();
 | |
|         })
 | |
|         .flatMap(user => {
 | |
|           if (!user) {
 | |
|             throw wrapHandledError(
 | |
|               new Error('could not find or create a user'),
 | |
|               {
 | |
|                 message: dedent`
 | |
|     Oops... something is not right. We could not find or create a
 | |
|     user with that email.
 | |
|                 `,
 | |
|                 type: 'info',
 | |
|                 redirectTo: '/'
 | |
|               }
 | |
|             );
 | |
|           }
 | |
|           const createToken = observeQuery(
 | |
|             AccessToken,
 | |
|             'create',
 | |
|             {
 | |
|               userId: user.id,
 | |
|               created: new Date(),
 | |
|               ttl: user.constructor.settings.ttl
 | |
|             }
 | |
|           );
 | |
|           const updateUser = user.update$({
 | |
|             emailVerified: true,
 | |
|             emailAuthLinkTTL: null,
 | |
|             emailVerifyTTL: null
 | |
|           });
 | |
|           return Observable.combineLatest(
 | |
|             Observable.of(user),
 | |
|             createToken,
 | |
|             updateUser,
 | |
|             (user, token) => ({user, token})
 | |
|           );
 | |
|         })
 | |
|         .subscribe(
 | |
|           ({ user, token }) => cb(null, user, null, token),
 | |
|           cb
 | |
|         );
 | |
| 
 | |
|     } else {
 | |
| 
 | |
|       return UserIdent.findOne$(query)
 | |
|         .flatMap(identity => {
 | |
|           return identity ?
 | |
|             Observable.of(identity.user()) :
 | |
|             User.findOne$({ where: { email } })
 | |
|               .flatMap(user => {
 | |
|                 return user ?
 | |
|                   Observable.of(user) :
 | |
|                   User.create$({ email }).toPromise();
 | |
|               });
 | |
|         })
 | |
|         .flatMap(user => {
 | |
| 
 | |
|           const createToken = observeQuery(
 | |
|             AccessToken,
 | |
|             'create',
 | |
|             {
 | |
|               userId: user.id,
 | |
|               created: new Date(),
 | |
|               ttl: user.constructor.settings.ttl
 | |
|             }
 | |
|           );
 | |
|           const updateUser = user.update$({
 | |
|             email: email,
 | |
|             emailVerified: true,
 | |
|             emailAuthLinkTTL: null,
 | |
|             emailVerifyTTL: null
 | |
|           });
 | |
|           return Observable.combineLatest(
 | |
|             Observable.of(user),
 | |
|             createToken,
 | |
|             updateUser,
 | |
|             (user, token) => ({ user, token })
 | |
|           );
 | |
|         })
 | |
|         .subscribe(
 | |
|           ({ user, token }) => cb(null, user, null, token),
 | |
|           cb
 | |
|         );
 | |
| 
 | |
|     }
 | |
|   };
 | |
| }
 |