Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 62x 1x 1x 1x 1x 1x 68x 68x 68x 2x 66x 66x 66x 66x 66x 66x 66x 66x 1x 4x 4x 4x 4x 4x 4x 1x 1x 95x 95x 95x 95x 95x 95x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { AppRouteImplementation } from "@ts-rest/express"; import { compareSaltedHash, saltedHash } from "@cooper/backend/src/lib/hashing"; import { addMinutes } from "date-fns"; import { contract } from "@cooper/ts-rest/src/contract"; import { authenticate } from "@cooper/backend/src/middleware/authenticate"; import guard from "@cooper/backend/src/middleware/guard"; export const login: AppRouteImplementation<typeof contract.public.auth.login> = async function ({ body, req, res }) { const db = req.app.locals.database; // Check if valid user const existingUser = db.auth.users.getUser(body.username); if (!existingUser) { return { status: 401, body: { error: "Invalid username or password", }, }; } // Check if username and password match const passwordMatch = compareSaltedHash(body.password, existingUser.password); Iif (!passwordMatch) { return { status: 401, body: { error: "Invalid username or password", }, }; } // Get session details const ip = req.ip ?? "Unknown"; const userAgent = req.get("user-agent") || "Unknown"; const newSession = db.auth.sessions.createSession( existingUser.username, ip, userAgent, new Date(), addMinutes(new Date(), 30), ); // Unexpected error here - there was an issue with the database layer Iif (newSession instanceof Error) { throw newSession; } // Set secure httpOnly cookie with new session tied to user res.cookie("id", newSession.sessionId, { secure: true, expires: newSession.expires, httpOnly: true, sameSite: "strict", }); return { status: 200, body: { message: "Logged in successfully", }, }; }; const logoutHandler: AppRouteImplementation<typeof contract.public.auth.logout> = async function ({ req, res }) { const db = req.app.locals.database; const sessionId = guard(res.session).sessionId; if (sessionId != null) { db.auth.sessions.deleteSession(sessionId); res.clearCookie("id"); return { status: 200, body: { message: "Logged out successfully", }, }; } return { status: 401, body: { error: "Unauthorised", }, }; }; export const logout = { middleware: [authenticate], handler: logoutHandler, }; export const signup: AppRouteImplementation<typeof contract.public.auth.signup> = async function ({ req, body }) { const db = req.app.locals.database; const existingUser = db.auth.users.getUser(body.username); Iif (existingUser) { return { status: 400, body: { error: "User already exists", }, }; } const newUser = db.auth.users.createUser({ username: body.username, firstName: body.firstName, lastName: body.lastName, password: saltedHash(body.password), }); Iif (newUser instanceof Error) { throw newUser; } return { status: 200, body: { message: "Signed up successfully", }, }; }; const getSessionsHandler: AppRouteImplementation<typeof contract.public.auth.getSessions> = async function ({ req, res, }) { const db = req.app.locals.database; const sessions = db.auth.sessions.getUserSessions(guard(res.session).username); return { status: 200, body: { sessions, }, }; }; export const getSessions = { middleware: [authenticate], handler: getSessionsHandler, }; const validSessionHandler: AppRouteImplementation<typeof contract.public.auth.validSession> = async function () { // "authed" middleware validates session beforehand, so always return success return { status: 200, body: { message: "Valid session", }, }; }; export const validSession = { middleware: [authenticate], handler: validSessionHandler, }; |