import { RequestHandler } from "../entities/RequestHandler"; import { AccountHelper } from "../helpers/AccountHelper"; import { UserHelper } from "../helpers/UserHelper"; import { NewAccount } from "../entities/NewAccount"; import { removeHTMLNodes } from "../utils/StringUtils"; import { limit_query } from "./APILimitsController"; import { Action } from "../helpers/APILimitsHelper"; import { UserController } from "./UserController"; import { PostsController } from "./PostsController"; import { CommentsController } from "./CommentsController"; /** * Account controller * * @author Pierre HUBERT */ export class AccountController { /** * Create a new account * * @param h Request handler */ public static async Create(h: RequestHandler) { // Limit request await limit_query(h, Action.CREATE_ACCOUNT, false); // Get & check email address const email = h.postEmail("emailAddress"); if(await AccountHelper.ExistsEmail(email)) h.error(409, "This email address already belongs to an account!"); const newAccount = { firstName: removeHTMLNodes(h.postString("firstName")), lastName: removeHTMLNodes(h.postString("lastName")), email: email, password: h.postString("password", 3) }; // Try to create the account await AccountHelper.Create(newAccount); // Trigger the API limit await limit_query(h, Action.CREATE_ACCOUNT, true); // Success h.success("The account has been created!"); } /** * Attempt to login user * * @param h Request handler */ public static async LoginUser(h: RequestHandler) { // Get post data const email = h.postEmail("userMail"); const password = h.postString("userPassword"); // Limit request await limit_query(h, Action.LOGIN_FAILED, false); // Authenticate user const tokens = await AccountHelper.LoginUser(email, password, h.getClientInfo()); if(tokens == null) { // Trigger limit await limit_query(h, Action.LOGIN_FAILED, true); h.error(401, "Invalid e-mail address / password !"); } // Success h.send({ success: "User signed in!", tokens: { token1: tokens.token1, token2: tokens.token2 } }); } /** * Disconnect user * * @param handler */ public static async LogoutUser(handler: RequestHandler) { await AccountHelper.DestroyUserTokens(handler.getClientInfo(), handler.getUserId()); handler.success("User has been disconnected!"); } /** * Get current user ID * * @param handler */ public static CurrentUserID(handler: RequestHandler) { handler.send({ userID: handler.getUserId() }); } /** * Check out whether an email is associated to an account * or not * * @param h Request handler */ public static async ExistsMail(h: RequestHandler) { const email = h.postEmail("email"); h.send({ exists: await AccountHelper.ExistsEmail(email) }) } /** * Check if an account associated with an email address has * setup security questions or not * * @param h Request handler */ public static async HasSecurityQuestions(h: RequestHandler) { const userID = await h.postUserIdFromEmail("email"); const settings = await UserHelper.GetUserInfo(userID); h.send({ defined: settings.hasSecurityQuestions }) } /** * Get the security questions of a user, in order to reset its * password * * @param h Request handler */ public static async GetSecurityQuestions(h: RequestHandler) { const userID = await h.postUserIdFromEmail("email"); const settings = await UserHelper.GetUserInfo(userID); if(!settings.hasSecurityQuestions) h.error(401, "Specified user has not setup security questions !"); h.send({ questions: [ settings.security_question_1, settings.security_question_2 ] }) } /** * Check the answer given by the user * * @param h Request handler */ public static async CheckSecurityAnswers(h: RequestHandler) { const userID = await h.postUserIdFromEmail("email"); const settings = await UserHelper.GetUserInfo(userID); if(!settings.hasSecurityQuestions) h.error(401, "Specified user has not setup security questions !"); // Get the answers of the user const answers = h.postString("answers", 3).split("&") .map((e) => decodeURIComponent(e).toLowerCase().trim()); if(answers.length != 2) h.error(401, "Please specify two security answers !"); // Check the answers if(answers[0] != settings.security_answer_1.toLowerCase().trim() || answers[1] != settings.security_answer_2.toLowerCase().trim()) h.error(401, "Specified ecurity answers are invalid!"); // If we get there, security answers are valid, we can create a password reset token h.send({ reset_token: await AccountHelper.GenerateNewPasswordResetToken(userID) }); } /** * Check the validity of a password reset Token * * @param h Request handler */ public static async CheckPasswordResetToken(h: RequestHandler) { // We just get user ID to check the validity of the token await this.GetUserIDFromPasswordResetToken(h, "token"); h.success("The token is valid."); } /** * Reset user password * * @param h Request handler */ public static async ResetUserPassword(h: RequestHandler) { const userID = await this.GetUserIDFromPasswordResetToken(h, "token"); const newPassword = h.postString("password", 3); // Set new password await AccountHelper.ChangePassword(userID, newPassword); // Destroy reset token await AccountHelper.DestroyPasswordResetTokenForUser(userID); h.success("Password changed!"); } /** * Export the data of the user * * @param h Request handler */ public static async ExportData(h: RequestHandler) { await h.needUserPostPassword("password"); // Query the database const data = await AccountHelper.Export(h.getUserId()); const out: any = { userID: data.userID, // General account information advanced_info: await UserController.UserToAPI(data.userInfo, h, true), // User posts posts: await Promise.all(data.postsList.map((p) => PostsController.PostToAPI(h, p))), // User comments comments: await CommentsController.CommentsToAPI(h, data.comments), }; // TODO : continue (additional user info) h.send(out); } /** * Delete a user account * * @param h Request handler */ public static async DeleteAccount(h: RequestHandler) { await h.needUserPostPassword("password"); // TODO : implement h.error(500, "Method not implemented yet."); } /** * Get the user ID associated to a password reset token * * @param h Request handler * @param name The name of the POST field containing the token */ private static async GetUserIDFromPasswordResetToken(h: RequestHandler, name: string) : Promise { const token = h.postString(name, 10); const userID = await AccountHelper.GetUserIDFromPasswordResetToken(token); if(userID < 1) h.error(401, "Invalid password reset token!"); return userID; } }