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:
@ -8,6 +8,8 @@ import { publicS3Endpoint, uploadToS3FromUrl } from '../utils/s3';
|
||||
import { sendEmail } from '../mailer';
|
||||
import { Star, Team, Collection, NotificationSetting, ApiKey } from '.';
|
||||
|
||||
const DEFAULT_AVATAR_HOST = 'https://tiley.herokuapp.com';
|
||||
|
||||
const User = sequelize.define(
|
||||
'user',
|
||||
{
|
||||
@ -29,6 +31,7 @@ const User = sequelize.define(
|
||||
lastActiveIp: { type: DataTypes.STRING, allowNull: true },
|
||||
lastSignedInAt: DataTypes.DATE,
|
||||
lastSignedInIp: { type: DataTypes.STRING, allowNull: true },
|
||||
lastSigninEmailSentAt: DataTypes.DATE,
|
||||
suspendedAt: DataTypes.DATE,
|
||||
suspendedById: DataTypes.UUID,
|
||||
},
|
||||
@ -38,6 +41,18 @@ const User = sequelize.define(
|
||||
isSuspended() {
|
||||
return !!this.suspendedAt;
|
||||
},
|
||||
avatarUrl() {
|
||||
const original = this.getDataValue('avatarUrl');
|
||||
if (original) {
|
||||
return original;
|
||||
}
|
||||
|
||||
const hash = crypto
|
||||
.createHash('md5')
|
||||
.update(this.email || '')
|
||||
.digest('hex');
|
||||
return `${DEFAULT_AVATAR_HOST}/avatar/${hash}/${this.name[0]}.png`;
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
@ -96,12 +111,28 @@ User.prototype.getJwtToken = function() {
|
||||
return JWT.sign({ id: this.id }, this.jwtSecret);
|
||||
};
|
||||
|
||||
User.prototype.getEmailSigninToken = function() {
|
||||
if (this.service && this.service !== 'email') {
|
||||
throw new Error('Cannot generate email signin token for OAuth user');
|
||||
}
|
||||
|
||||
return JWT.sign(
|
||||
{ id: this.id, createdAt: new Date().toISOString() },
|
||||
this.jwtSecret
|
||||
);
|
||||
};
|
||||
|
||||
const uploadAvatar = async model => {
|
||||
const endpoint = publicS3Endpoint();
|
||||
const { avatarUrl } = model;
|
||||
|
||||
if (model.avatarUrl && !model.avatarUrl.startsWith(endpoint)) {
|
||||
if (
|
||||
avatarUrl &&
|
||||
!avatarUrl.startsWith(endpoint) &&
|
||||
!avatarUrl.startsWith(DEFAULT_AVATAR_HOST)
|
||||
) {
|
||||
const newUrl = await uploadToS3FromUrl(
|
||||
model.avatarUrl,
|
||||
avatarUrl,
|
||||
`avatars/${model.id}/${uuid.v4()}`
|
||||
);
|
||||
if (newUrl) model.avatarUrl = newUrl;
|
||||
@ -126,7 +157,7 @@ const removeIdentifyingInfo = async (model, options) => {
|
||||
transaction: options.transaction,
|
||||
});
|
||||
|
||||
model.email = '';
|
||||
model.email = null;
|
||||
model.name = 'Unknown';
|
||||
model.avatarUrl = '';
|
||||
model.serviceId = null;
|
||||
@ -165,7 +196,7 @@ User.afterCreate(async user => {
|
||||
// From Slack support:
|
||||
// If you wish to contact users at an email address obtained through Slack,
|
||||
// you need them to opt-in through a clear and separate process.
|
||||
if (!team.slackId) {
|
||||
if (user.service && user.service !== 'slack') {
|
||||
sendEmail('welcome', user.email, { teamUrl: team.url });
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user