CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/pages/api/v2/auth/password-reset.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Password reset works as follows:
8
9
1. Query the database to make sure there is a user with the given email address.
10
2. If a password reset was already sent within the last XX minutes,
11
return an error -- we don't want people to spam other people with
12
password resets.
13
3. Generate password reset token and write to database.
14
4. Send email.
15
5. Send response to user that email has been sent (or there was an error).
16
*/
17
18
import isAccountAvailable from "@cocalc/server/auth/is-account-available";
19
import {
20
recentAttempts,
21
createReset,
22
} from "@cocalc/server/auth/password-reset";
23
import sendPasswordResetEmail from "@cocalc/server/email/password-reset";
24
import getParams from "lib/api/get-params";
25
26
export default async function passwordReset(req, res) {
27
const { email } = getParams(req);
28
let result;
29
try {
30
result = await handle(email?.toLowerCase(), req.ip);
31
} catch (err) {
32
result = { error: err.message };
33
}
34
res.json(result);
35
}
36
37
async function handle(email: string, ip: string): Promise<object> {
38
if (await isAccountAvailable(email)) {
39
// Bad -- email is *available*, which means no way to reset
40
// the password for it, since it doesn't exist.
41
return { error: `There is no account with email "${email}".` };
42
}
43
// Check that user isn't spamming email.
44
45
const n = await recentAttempts(email, ip);
46
if (n > 3) {
47
return {
48
error: `We recently sent multiple password resets for "${email}". Check your email or wait a while and try later.`,
49
};
50
}
51
52
const id = await createReset(email, ip, 60 * 60 * 4); // 4 hour ttl seems reasonable for this.
53
// TODO:
54
// - Send email with the id and link
55
// - Link should be back to next.js server (i.e., a new password reset target)
56
// - Implement that target and backend handling of it.
57
try {
58
await sendPasswordResetEmail(email, id);
59
} catch (err) {
60
console.trace(err);
61
return {
62
error: `Sending password reset email failed -- ${err.message}`,
63
};
64
}
65
66
return {
67
success: `Password reset email successfully sent to ${email}.`,
68
};
69
}
70
71