| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  | import { Observable } from 'rx'; | 
					
						
							|  |  |  | // import debug from 'debug';
 | 
					
						
							|  |  |  | import dedent from 'dedent'; | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  | import { isEmail } from 'validator'; | 
					
						
							| 
									
										
										
										
											2015-06-11 11:38:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  | import { observeMethod, observeQuery } from '../../server/utils/rx'; | 
					
						
							|  |  |  | import { wrapHandledError } from '../../server/utils/create-handled-error.js'; | 
					
						
							| 
									
										
										
										
											2015-08-12 12:15:19 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  | // const log = debug('fcc:models:userIdent');
 | 
					
						
							| 
									
										
										
										
											2015-06-11 11:38:08 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-24 11:53:29 +01:00
										 |  |  | export function ensureLowerCaseEmail(profile) { | 
					
						
							|  |  |  |   return typeof profile?.emails?.[0]?.value === 'string' | 
					
						
							|  |  |  |     ? profile.emails[0].value.toLowerCase() | 
					
						
							|  |  |  |     : ''; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-04 14:52:06 -07:00
										 |  |  | export default function(UserIdent) { | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |   UserIdent.on('dataSourceAttached', () => { | 
					
						
							|  |  |  |     UserIdent.findOne$ = observeMethod(UserIdent, 'findOne'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |   UserIdent.login = function( | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |     _provider, | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |     authScheme, | 
					
						
							|  |  |  |     profile, | 
					
						
							|  |  |  |     credentials, | 
					
						
							|  |  |  |     options, | 
					
						
							|  |  |  |     cb | 
					
						
							|  |  |  |   ) { | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |     const User = UserIdent.app.models.User; | 
					
						
							|  |  |  |     const AccessToken = UserIdent.app.models.AccessToken; | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |     options = options || {}; | 
					
						
							|  |  |  |     if (typeof options === 'function' && !cb) { | 
					
						
							|  |  |  |       cb = options; | 
					
						
							|  |  |  |       options = {}; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  |     // get the social provider data and the external id from auth0
 | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |     profile.id = profile.id || profile.openid; | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |     const auth0IdString = '' + profile.id; | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |     const [provider, socialExtId] = auth0IdString.split('|'); | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |     const query = { | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |       where: { | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |         provider: provider, | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |         externalId: socialExtId | 
					
						
							| 
									
										
										
										
											2017-07-13 11:39:07 -07:00
										 |  |  |       }, | 
					
						
							|  |  |  |       include: 'user' | 
					
						
							| 
									
										
										
										
											2016-04-21 20:35:19 -07:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |     // get the email from the auth0 (its expected from social providers)
 | 
					
						
							| 
									
										
										
										
											2020-04-24 11:53:29 +01:00
										 |  |  |     const email = ensureLowerCaseEmail(profile); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |     if (!isEmail('' + email)) { | 
					
						
							|  |  |  |       throw wrapHandledError( | 
					
						
							| 
									
										
										
										
											2019-09-10 00:02:40 +01:00
										 |  |  |         new Error('invalid or empty email received from auth0'), | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |         { | 
					
						
							|  |  |  |           message: dedent`
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:31:03 +01:00
										 |  |  |     ${provider} did not return a valid email address. | 
					
						
							|  |  |  |     Please try again with a different account that has an | 
					
						
							|  |  |  |     email associated with it your update your settings on ${provider}, for us to be able to retrieve your email. | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |           `,
 | 
					
						
							|  |  |  |           type: 'info', | 
					
						
							|  |  |  |           redirectTo: '/' | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |     if (provider === 'email') { | 
					
						
							| 
									
										
										
										
											2019-10-19 01:09:29 +05:30
										 |  |  |       return User.findOne$({ where: { email } }) | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |         .flatMap(user => { | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |           return user | 
					
						
							|  |  |  |             ? Observable.of(user) | 
					
						
							|  |  |  |             : User.create$({ email }).toPromise(); | 
					
						
							| 
									
										
										
										
											2018-05-22 18:10:00 +05:30
										 |  |  |         }) | 
					
						
							|  |  |  |         .flatMap(user => { | 
					
						
							|  |  |  |           if (!user) { | 
					
						
							|  |  |  |             throw wrapHandledError( | 
					
						
							| 
									
										
										
										
											2018-05-22 21:56:12 +05:30
										 |  |  |               new Error('could not find or create a user'), | 
					
						
							| 
									
										
										
										
											2018-05-22 18:10:00 +05:30
										 |  |  |               { | 
					
						
							|  |  |  |                 message: dedent`
 | 
					
						
							| 
									
										
										
										
											2019-06-19 15:31:03 +01:00
										 |  |  |     We could not find or create a user with that email address. | 
					
						
							| 
									
										
										
										
											2018-05-22 18:10:00 +05:30
										 |  |  |                 `,
 | 
					
						
							|  |  |  |                 type: 'info', | 
					
						
							|  |  |  |                 redirectTo: '/' | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |           const createToken = observeQuery(AccessToken, 'create', { | 
					
						
							|  |  |  |             userId: user.id, | 
					
						
							|  |  |  |             created: new Date(), | 
					
						
							|  |  |  |             ttl: user.constructor.settings.ttl | 
					
						
							| 
									
										
										
										
											2018-05-22 18:10:00 +05:30
										 |  |  |           }); | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |           const updateUserPromise = new Promise((resolve, reject) => | 
					
						
							|  |  |  |             user.updateAttributes( | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 emailVerified: true, | 
					
						
							|  |  |  |                 emailAuthLinkTTL: null, | 
					
						
							|  |  |  |                 emailVerifyTTL: null | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               err => { | 
					
						
							|  |  |  |                 if (err) { | 
					
						
							|  |  |  |                   return reject(err); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return resolve(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           ); | 
					
						
							| 
									
										
										
										
											2018-05-22 00:37:01 +05:30
										 |  |  |           return Observable.combineLatest( | 
					
						
							|  |  |  |             Observable.of(user), | 
					
						
							|  |  |  |             createToken, | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |             Observable.fromPromise(updateUserPromise), | 
					
						
							|  |  |  |             (user, token) => ({ user, token }) | 
					
						
							| 
									
										
										
										
											2018-05-22 00:37:01 +05:30
										 |  |  |           ); | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |         }) | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |         .subscribe(({ user, token }) => cb(null, user, null, token), cb); | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |     } else { | 
					
						
							|  |  |  |       return UserIdent.findOne$(query) | 
					
						
							|  |  |  |         .flatMap(identity => { | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |           return identity | 
					
						
							|  |  |  |             ? Observable.of(identity.user()) | 
					
						
							|  |  |  |             : User.findOne$({ where: { email } }).flatMap(user => { | 
					
						
							| 
									
										
										
										
											2019-02-18 19:32:49 +00:00
										 |  |  |                 return user | 
					
						
							|  |  |  |                   ? Observable.of(user) | 
					
						
							|  |  |  |                   : User.create$({ email }).toPromise(); | 
					
						
							|  |  |  |               }); | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |         }) | 
					
						
							|  |  |  |         .flatMap(user => { | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |           const createToken = observeQuery(AccessToken, 'create', { | 
					
						
							|  |  |  |             userId: user.id, | 
					
						
							|  |  |  |             created: new Date(), | 
					
						
							|  |  |  |             ttl: user.constructor.settings.ttl | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2018-11-12 16:58:34 +00:00
										 |  |  |           const updateUser = new Promise((resolve, reject) => | 
					
						
							|  |  |  |             user.updateAttributes( | 
					
						
							|  |  |  |               { | 
					
						
							|  |  |  |                 email: email, | 
					
						
							|  |  |  |                 emailVerified: true, | 
					
						
							|  |  |  |                 emailAuthLinkTTL: null, | 
					
						
							|  |  |  |                 emailVerifyTTL: null | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |               err => { | 
					
						
							|  |  |  |                 if (err) { | 
					
						
							|  |  |  |                   return reject(err); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return resolve(); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           ); | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |           return Observable.combineLatest( | 
					
						
							| 
									
										
										
										
											2018-05-20 13:40:15 +05:30
										 |  |  |             Observable.of(user), | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |             createToken, | 
					
						
							| 
									
										
										
										
											2018-11-12 16:58:34 +00:00
										 |  |  |             Observable.fromPromise(updateUser), | 
					
						
							| 
									
										
										
										
											2018-06-28 20:27:15 +05:30
										 |  |  |             (user, token) => ({ user, token }) | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |           ); | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2018-09-20 10:22:45 +01:00
										 |  |  |         .subscribe(({ user, token }) => cb(null, user, null, token), cb); | 
					
						
							| 
									
										
										
										
											2018-05-19 21:21:49 +05:30
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2015-08-12 19:08:05 -07:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2015-08-04 14:52:06 -07:00
										 |  |  | } |