feat: Guest email authentication (#1088)
* feat: API endpoints for email signin * fix: After testing * Initial signin flow working * move shared middleware * feat: Add guest signin toggle, obey on endpoints * feat: Basic email signin when enabled * Improve guest signin email Disable double signin with JWT * fix: Simple rate limiting * create placeholder users in db * fix: Give invited users default avatar add invited users to people settings * test * add transaction * tmp: test CI * derp * md5 * urgh * again * test: pass * test * fix: Remove usage of data values * guest signin page * Visually separator 'Invited' from other people tabs * fix: Edge case attempting SSO signin for guest email account * fix: Correctly set email auth method to cookie * Improve rate limit error display * lint: cleanup / comments * Improve invalid token error display * style tweaks * pass guest value to subdomain * Restore copy link option * feat: Allow invite revoke from people management * fix: Incorrect users email schema does not allow for user deletion * lint * fix: avatarUrl for deleted user failure * change default to off for guest invites * fix: Changing security settings wipes subdomain * fix: user delete permissioning * test: Add user.invite specs
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
// @flow
|
||||
import Sequelize from 'sequelize';
|
||||
import crypto from 'crypto';
|
||||
import Router from 'koa-router';
|
||||
import { capitalize } from 'lodash';
|
||||
@ -6,6 +7,8 @@ import { OAuth2Client } from 'google-auth-library';
|
||||
import { User, Team, Event } from '../models';
|
||||
import auth from '../middlewares/authentication';
|
||||
|
||||
const Op = Sequelize.Op;
|
||||
|
||||
const router = new Router();
|
||||
const client = new OAuth2Client(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
@ -77,46 +80,75 @@ router.get('google.callback', auth({ required: false }), async ctx => {
|
||||
},
|
||||
});
|
||||
|
||||
const [user, isFirstSignin] = await User.findOrCreate({
|
||||
where: {
|
||||
service: 'google',
|
||||
serviceId: profile.data.id,
|
||||
teamId: team.id,
|
||||
},
|
||||
defaults: {
|
||||
name: profile.data.name,
|
||||
email: profile.data.email,
|
||||
isAdmin: isFirstUser,
|
||||
avatarUrl: profile.data.picture,
|
||||
},
|
||||
});
|
||||
|
||||
if (isFirstSignin) {
|
||||
await Event.create({
|
||||
name: 'users.create',
|
||||
actorId: user.id,
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
data: {
|
||||
name: user.name,
|
||||
service: 'google',
|
||||
try {
|
||||
const [user, isFirstSignin] = await User.findOrCreate({
|
||||
where: {
|
||||
[Op.or]: [
|
||||
{
|
||||
service: 'google',
|
||||
serviceId: profile.data.id,
|
||||
},
|
||||
{
|
||||
service: '',
|
||||
},
|
||||
],
|
||||
teamId: team.id,
|
||||
},
|
||||
defaults: {
|
||||
name: profile.data.name,
|
||||
email: profile.data.email,
|
||||
isAdmin: isFirstUser,
|
||||
avatarUrl: profile.data.picture,
|
||||
},
|
||||
ip: ctx.request.ip,
|
||||
});
|
||||
}
|
||||
|
||||
// update email address if it's changed in Google
|
||||
if (!isFirstSignin && profile.data.email !== user.email) {
|
||||
await user.update({ email: profile.data.email });
|
||||
}
|
||||
if (isFirstSignin) {
|
||||
await Event.create({
|
||||
name: 'users.create',
|
||||
actorId: user.id,
|
||||
userId: user.id,
|
||||
teamId: team.id,
|
||||
data: {
|
||||
name: user.name,
|
||||
service: 'google',
|
||||
},
|
||||
ip: ctx.request.ip,
|
||||
});
|
||||
}
|
||||
|
||||
if (isFirstUser) {
|
||||
await team.provisionFirstCollection(user.id);
|
||||
await team.provisionSubdomain(hostname);
|
||||
}
|
||||
// update email address if it's changed in Google
|
||||
if (!isFirstSignin && profile.data.email !== user.email) {
|
||||
await user.update({ email: profile.data.email });
|
||||
}
|
||||
|
||||
// set cookies on response and redirect to team subdomain
|
||||
ctx.signIn(user, team, 'google', isFirstSignin);
|
||||
if (isFirstUser) {
|
||||
await team.provisionFirstCollection(user.id);
|
||||
await team.provisionSubdomain(hostname);
|
||||
}
|
||||
|
||||
// set cookies on response and redirect to team subdomain
|
||||
ctx.signIn(user, team, 'google', isFirstSignin);
|
||||
} catch (err) {
|
||||
if (err instanceof Sequelize.UniqueConstraintError) {
|
||||
const exists = await User.findOne({
|
||||
where: {
|
||||
service: 'email',
|
||||
email: profile.data.email,
|
||||
teamId: team.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (exists) {
|
||||
ctx.redirect(`${team.url}?notice=email-auth-required`);
|
||||
} else {
|
||||
ctx.redirect(`${team.url}?notice=auth-error`);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
Reference in New Issue
Block a user