Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/pages/api/v2/auth/sign-in.ts
5994 views
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
Sign in works as follows:
8
9
1. Query the database for the account_id and password_hash
10
with the given username.
11
12
2. Use the password-hash library to determine whether or
13
not the given password hashes properly. If so, create and
14
set a secure remember_me http cookie confirming that the
15
client is that user and tell user they are now authenticated.
16
If not, send an error back.
17
*/
18
import { Request, Response } from "express";
19
20
import getPool from "@cocalc/database/pool";
21
import { recordFail, signInCheck } from "@cocalc/server/auth/throttle";
22
import getParams from "lib/api/get-params";
23
import { verify } from "password-hash";
24
import { MAX_PASSWORD_LENGTH } from "@cocalc/util/auth";
25
import setSignInCookies from "@cocalc/server/auth/set-sign-in-cookies";
26
27
export default async function signIn(req: Request, res: Response) {
28
let { email, password } = getParams(req);
29
30
email = email.toLowerCase().trim();
31
32
const check: string | undefined = await signInCheck(email, req.ip);
33
if (check) {
34
res.json({ error: check });
35
return;
36
}
37
let account_id: string;
38
39
try {
40
// Don't bother checking reCaptcha for *sign in* for now, since it causes trouble
41
// when large classes all sign in from one point. Also, it's much less important
42
// for sign in, than for sign up and payment.
43
// await reCaptcha(req);
44
account_id = await getAccount(email, password);
45
} catch (err) {
46
res.json({ error: `Problem signing into account -- ${err.message}.` });
47
recordFail(email, req.ip);
48
return;
49
}
50
51
await signUserIn(req, res, account_id);
52
}
53
54
export async function getAccount(
55
email_address: string,
56
password: string,
57
): Promise<string> {
58
if (password.length > MAX_PASSWORD_LENGTH) {
59
throw new Error(
60
`The password must be shorter than ${MAX_PASSWORD_LENGTH} characters.`,
61
);
62
}
63
64
const pool = getPool();
65
const { rows } = await pool.query(
66
"SELECT account_id, password_hash, banned FROM accounts WHERE email_address=$1",
67
[email_address],
68
);
69
if (rows.length == 0) {
70
throw Error(`no account with email address '${email_address}'`);
71
}
72
const { account_id, password_hash, banned } = rows[0];
73
if (banned) {
74
throw Error(
75
`'${email_address}' is banned -- if you think this is a mistake, please email [email protected] and explain.`,
76
);
77
}
78
if (!verify(password, password_hash)) {
79
throw Error(`password for '${email_address}' is incorrect`);
80
}
81
return account_id;
82
}
83
84
export async function signUserIn(
85
req,
86
res,
87
account_id: string,
88
opts?: { maxAge?: number },
89
): Promise<void> {
90
try {
91
await setSignInCookies({
92
req,
93
res,
94
account_id,
95
maxAge: opts?.maxAge,
96
});
97
} catch (err) {
98
res.json({ error: `Problem setting auth cookies -- ${err}` });
99
return;
100
}
101
res.json({ account_id });
102
}
103
104