diff --git a/src/controllers/accountController.ts b/src/controllers/accountController.ts index 132060a..e6947c5 100644 --- a/src/controllers/accountController.ts +++ b/src/controllers/accountController.ts @@ -165,21 +165,21 @@ export const verifyEmail = async (creds: ResetCredentials): PromiseRequest a new one.', }; - const resetRequest = await VerifyEmailRequestModel.findById(creds.id); - if (!resetRequest) { + const verifyRequest = await VerifyEmailRequestModel.findById(creds.id); + if (!verifyRequest) { throw new HttpException(400, { ...invalidProps, message: `Email verification ID ${creds.id} did not match any request`, }); } - if (!(await argon2.verify(resetRequest.key, creds.key as string))) { + if (!(await argon2.verify(verifyRequest.key, creds.key as string))) { throw new HttpException(400, { ...invalidProps, message: 'Email verification key did not match database', }); } - return resetRequest; + return verifyRequest; }; export const doPasswordReset = async (params: PasswordResetRequestParams) => { @@ -280,6 +280,7 @@ export const isEmailAvailable = async (email: string): Promise => { const [inDatabase, inPending] = await Promise.all([ searchAsync(ldapClient, ldapEscape.filter`(swatmail=${email})`), TaskModel.exists({ 'data.email': email, status: 'pending' }), + VerifyEmailRequestModel.exists({ 'data.email': email }), ]); if (inDatabase || inPending) { diff --git a/src/functions/createAccount.ts b/src/functions/createAccount.ts index 9cb019c..90cc376 100644 --- a/src/functions/createAccount.ts +++ b/src/functions/createAccount.ts @@ -115,9 +115,4 @@ export const createAccount = async (data: any) => { subject: 'Verify your SCCS account', html: emailText, }); - - const msgUrl = nodemailer.getTestMessageUrl(info); - if (msgUrl) { - logger.debug(`View message at ${msgUrl}`); - } }; diff --git a/src/integration/models.ts b/src/integration/models.ts index d10a550..84f877c 100644 --- a/src/integration/models.ts +++ b/src/integration/models.ts @@ -88,13 +88,12 @@ export const PasswordResetRequestModel = mongoose.model( export interface VerifyEmailRequest { // verification email links generate two keys: the ID, which is stored plain, and the key, which is // hashed with argon2 before being stored. - // good chance the rest of this shit is wrong in this implementation: // Both are provided to the user and they make a request; // then we look up the request for the ID and compare hashed keys, basically exactly like a normal // username/password login flow. _id: string; key: string; - user: string; + email: string; timestamp: Date; suppressEmail?: boolean; } @@ -108,10 +107,10 @@ const verifyEmailRequestSchema = new mongoose.Schema({ type: String, required: true, }, - user: { + email: { type: String, required: true, - index: true, // we'll search by user to invalidate previous reset requests + index: true, }, timestamp: { type: Date, diff --git a/src/routes/account.ts b/src/routes/account.ts index 84e58d2..dee6203 100644 --- a/src/routes/account.ts +++ b/src/routes/account.ts @@ -99,7 +99,7 @@ router.get( }), ); -router.get( +router.post( '/init', catchErrors(async (req, res, next) => { const { error, value } = jf.validateAsClass(req.query, controller.ResetCredentials); @@ -109,14 +109,14 @@ router.get( } // I have no idea why joiful throws a fit here but this is the necessary workaround - const verifyEmail = await controller.verifyPasswordReset( + const verifyEmail = await controller.verifyEmail( value as unknown as controller.ResetCredentials, ); - return res.render('verify email', { + return res.render('accountInit', { id: value.id, key: value.key, - username: verifyEmail.user, + email: verifyEmail.email, }); }), ); diff --git a/views/createAccount.pug b/views/createAccount.pug index b155547..374adcf 100644 --- a/views/createAccount.pug +++ b/views/createAccount.pug @@ -7,7 +7,7 @@ include include/sauce-common | SCCS accounts are available to all Swarthmore students, faculty, | and staff—and you'll still be able to access it after | graduation. - form#createForm.form-signin.needs-validation(action='/account/create', method='post', novalidate) + form#createForm.form-signin.needs-validation(action='/account/init', method='post', novalidate) .form-group.mb-3 .form-floating script(type='text/javascript'). diff --git a/views/verifyEmailSuccess.pug b/views/verifyEmailSuccess.pug new file mode 100644 index 0000000..0674b9f --- /dev/null +++ b/views/verifyEmailSuccess.pug @@ -0,0 +1,9 @@ +include include/sauce-common + ++sauce-layout('Your request has been submitted!')(hideNavbar, includeBootstrapScripts) + h1.mb-4 We've sent you an email, follow the instructions to complete setting up your SCCS account + p. + To prevent abuse, SCCS staff manually approve all account creation + requests. When classes are in session, this usually happens within a + few hours. Once you've been approved, you'll get an email at + #{ email } with a link to set your password.