156 lines
4.6 KiB
JavaScript
156 lines
4.6 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 = new Promise((resolve, reject) =>
|
|
user.updateAttributes(
|
|
{
|
|
email: email,
|
|
emailVerified: true,
|
|
emailAuthLinkTTL: null,
|
|
emailVerifyTTL: null
|
|
},
|
|
err => {
|
|
if (err) {
|
|
return reject(err);
|
|
}
|
|
return resolve();
|
|
}
|
|
)
|
|
);
|
|
return Observable.combineLatest(
|
|
Observable.of(user),
|
|
createToken,
|
|
Observable.fromPromise(updateUser),
|
|
(user, token) => ({ user, token })
|
|
);
|
|
})
|
|
.subscribe(({ user, token }) => cb(null, user, null, token), cb);
|
|
}
|
|
};
|
|
}
|