An AI assistant wrote the shop's sign-up route. It answers 201 and looks fine, but look at what it saves:
app.post("/signup", (req: Request, res: Response) => {
const data = req.body;
const result = db.prepare("INSERT INTO users (email, password_hash) VALUES (?, ?)").run(data.email, data.password);
res.status(201).json({ id: result.lastInsertRowid, email: data.email });
});
The column is called password_hash, but it holds the password itself. Anyone who sees the database (a backup, a leak) reads every password, and people reuse passwords on other sites. It also breaks the login: the shop's /login route, already written for you, checks passwords with checkPassword, which expects a hash. With the AI's sign-up, every login answers 401.
A hash is a one-way scramble: the password gives the hash, but the hash never gives the password back. hashPassword(password: string): string, a function already written at the top of the file, mixes in a random salt first, so two people with the same password get different hashes. checkPassword(passwordHash: string, password: string): boolean, right below it, tells you whether a password fits a saved hash:
const stored = hashPassword("open sesame"); // a string
console.log(stored.slice(0, 17)); // scrypt:32768:8:1$
console.log(checkPassword(stored, "open sesame")); // true
console.log(checkPassword(stored, "Open sesame")); // false
The requests and the answers your app must give. GET /check/users is a checking route the course adds: it shows the users table with each salt and hash replaced by a label like <salt 1>.
POST /signup {"email": "ana@example.com", "password": "secret123"} → 201 {"email": "ana@example.com", "id": 1}
POST /signup {"email": "ben@example.com", "password": "secret123"} → 201 {"email": "ben@example.com", "id": 2}
GET /check/users → 200 [{"email": "ana@example.com", "id": 1, "password_hash": "scrypt:32768:8:1$<salt 1>$<hash 1>"},
{"email": "ben@example.com", "id": 2, "password_hash": "scrypt:32768:8:1$<salt 2>$<hash 2>"}]
POST /login {"email": "ana@example.com", "password": "secret123"} → 200 {"email": "ana@example.com", "id": 1}
POST /login {"email": "ana@example.com", "password": "Secret123"} → 401 {"error": "Wrong email or password"}
POST /login {"email": "ben@example.com", "password": "secret123"} → 200 {"email": "ben@example.com", "id": 2}
Your task: rewrite the function of the /signup route. Save the email and hashPassword of the password, never the password itself, and answer 201 with the new user's id and email.
Assignment
Follow the Coding Tutorial to rewrite the /signup route so it stores a salted hash instead of the password.
Hint
The /login route is already correct: it only needs a real hash in the column. hashPassword is already in the file, near the top, and its return type tells TypeScript that the hash is a string. Keep both the password and the hash out of the answer.
Free plan: 30 tutor messages. PRO is unlimited.
