146 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.3 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 updateUserPromise = new Promise((resolve, reject) =>
 | 
						|
            user.updateAttributes(
 | 
						|
              {
 | 
						|
                emailVerified: true,
 | 
						|
                emailAuthLinkTTL: null,
 | 
						|
                emailVerifyTTL: null
 | 
						|
              },
 | 
						|
              err => {
 | 
						|
                if (err) {
 | 
						|
                  return reject(err);
 | 
						|
                }
 | 
						|
                return resolve();
 | 
						|
              }
 | 
						|
            )
 | 
						|
          );
 | 
						|
          return Observable.combineLatest(
 | 
						|
            Observable.of(user),
 | 
						|
            createToken,
 | 
						|
            Observable.fromPromise(updateUserPromise),
 | 
						|
            (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);
 | 
						|
    }
 | 
						|
  };
 | 
						|
}
 |