UNPKG

@replyke/express

Version:

Replyke: Build interactive apps with social features like comments, votes, feeds, user lists, notifications, and more.

123 lines (122 loc) 4.99 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const models_1 = require("../../../models"); const authentication_1 = require("../../../helpers/authentication"); const models_2 = require("../../../models"); const reduceAuthenticatedUserDetails_1 = __importDefault(require("../../../helpers/reduceAuthenticatedUserDetails")); const config_1 = require("../../../config"); exports.default = async (req, res) => { const { email, password } = req.body; if (!email || !password) { res.status(400).json({ error: "Email, and password are required.", code: "auth/missing-fields", }); return; } const project = req.project; const projectId = project.id; try { // get the target model for that alias: const SuspensionModel = models_1.User.associations.suspensions .target; const ActiveSuspensionModel = SuspensionModel.scope({ method: ["active", new Date()], }); // Find user by username using Sequelize const userWithSuspensions = (await models_1.User.findOne({ where: { projectId, email }, include: [ { model: ActiveSuspensionModel, as: "suspensions", required: false, }, ], })); if (!userWithSuspensions) { res.status(403).json({ error: "User not found.", code: "auth/no-user-found", }); return; } const { salt, hash } = userWithSuspensions; if (!salt || !hash) { res.status(403).json({ error: "Invalid credentials.", code: "auth/invalid-credentials", }); return; } // Validate password const isValid = (0, authentication_1.verifyPassword)(password, hash, salt); // If isn't valid if (!isValid) { res.status(401).json({ error: "Incorrect password.", code: "auth/wrong-password", }); return; } const { sequelize, refreshTokenSecret } = (0, config_1.getCoreConfig)(); // Wrap the token generation and database save in a transaction const result = await sequelize.transaction(async (t) => { // Create an empty Token entry (UUID will be generated here) const refreshTokenEntry = (await models_2.Token.create({ userId: userWithSuspensions.id, projectId, }, { transaction: t } // Ensure this is part of the transaction )); // Generate the JWT for the refresh token const refreshTokenJWT = jsonwebtoken_1.default.sign({ sub: userWithSuspensions.id, // Subject, representing the user ID projectId, // Project ID aud: "replyke.com", // Audience iss: "replyke.com", // Issuer jti: refreshTokenEntry.id, // Use the token ID as the JWT ID }, refreshTokenSecret, { expiresIn: "30d" } // Refresh token expiry ); // Update the Token with the generated JWT and save it refreshTokenEntry.refreshToken = refreshTokenJWT; await refreshTokenEntry.save({ transaction: t }); // Generate the access token const accessTokenJWT = jsonwebtoken_1.default.sign({ sub: userWithSuspensions.id, // Subject, representing the user ID projectId, // Project ID role: "user", // User role aud: "replyke.com", // Audience iss: "replyke.com", // Issuer }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: "30m" } // Access token expiry ); return { accessTokenJWT, refreshTokenJWT }; }); const { refreshTokenJWT, accessTokenJWT } = result; const reducedAuthenticatedUser = (0, reduceAuthenticatedUserDetails_1.default)(userWithSuspensions); res.cookie("replyke-refresh-jwt", refreshTokenJWT, { httpOnly: true, sameSite: "none", secure: true, maxAge: 30 * 24 * 60 * 60 * 1000, path: "/", }); res.status(200).json({ success: true, accessToken: accessTokenJWT, refreshToken: refreshTokenJWT, user: reducedAuthenticatedUser, }); } catch (err) { console.error("Error signing user in:", err); res.status(500).json({ error: "Internal server error.", code: "auth/server-error", details: err.message, }); } };