import { crypt, sha1, randomStr } from "../utils/CryptUtils"; import { APIClient } from "../entities/APIClient"; import { UserLoginTokens } from "../entities/UserLoginTokens"; import { DatabaseHelper } from "./DatabaseHelper"; import { UserHelper } from "./UserHelper"; import { time, mysql_date } from "../utils/DateUtils"; import { NewAccount } from "../entities/NewAccount"; import { GeneralSettings, UserPageStatus, LangSettings, SecuritySettings } from "../entities/User"; import { AccountExport } from "../entities/AccountExport"; import { PostsHelper } from "./PostsHelper"; import { CommentsHelper } from "./CommentsHelper"; import { LikesHelper } from "./LikesHelper"; import { SurveyHelper } from "./SurveyHelper"; import { MoviesHelper } from "./MoviesHelper"; import { ConversationsHelper } from "./ConversationsHelper"; /** * Account helper * * @author Pierre HUBERT */ export const USER_TABLE = "utilisateurs"; const USERS_TOKENS_TABLE = "comunic_api_users_tokens"; export class AccountHelper { /** * Create a new account * * @param info Information about the new account */ public static async Create(info: NewAccount) { const data = { nom: info.lastName, prenom: info.firstName, date_creation: mysql_date(), mail: info.email, password: this.CryptPassword(info.password) }; await DatabaseHelper.InsertRow(USER_TABLE, data); } /** * Given email address and password, try to sign in user * * @param email The email of the user * @param password User password * @param client Information about associated client / null if none found */ static async LoginUser(email: string, password: string, client: APIClient) : Promise { // Perform a request on the database const row = await DatabaseHelper.QueryRow({ table: USER_TABLE, fields: ["ID"], where: { mail: email, password: this.CryptPassword(password) } }); // Check if user was found if(row == null) return null; const userID = row.ID; // Check for existing tokens let tokens = await this.GetClientTokens(userID, client); if(tokens != null) return tokens; const newTokens : UserLoginTokens = { userID: userID, clientID: client.id, token1: randomStr(150), token2: "dummy_data" } // Save new tokens await DatabaseHelper.InsertRow(USERS_TOKENS_TABLE, { user_id: newTokens.userID, service_id: newTokens.clientID, token1: newTokens.token1, token2: newTokens.token2 }); return newTokens; } /** * Get user client tokens (if it exists) * * @param userID Target user ID * @param client Information about associated client / null if none found */ private static async GetClientTokens(userID: number, client: APIClient): Promise { const row = await DatabaseHelper.QueryRow({ table: USERS_TOKENS_TABLE, where: { user_id: userID, service_id: client.id } }); return row == null ? null : this.DBToUserTokens(row); } /** * Find a user using its tokens * * @param client Information about the client * @param token1 First token * @param token2 Second token * @returns The ID of the target user / -1 if none found */ public static async GetUserIdFromTokens(client : APIClient, token1: string, token2: string) : Promise { const row = await DatabaseHelper.QueryRow({ table: USERS_TOKENS_TABLE, fields: ["user_id"], where: { service_id: client.id, token1: token1, token2: token2 } }); if(!row) return -1; return Number(row.user_id); } /** * Destroy user tokens * * @param client Information about the client * @param userID Target user ID */ public static async DestroyUserTokens(client: APIClient, userID: number) { return DatabaseHelper.DeleteRows(USERS_TOKENS_TABLE, { service_id: client.id, user_id: userID }); } /** * Check out whether the password of a user is valid * or not * * @param userID Target user ID * @param password Target password */ public static async CheckUserPassword(userID: number, password: string) : Promise { const crypt_pass = this.CryptPassword(password); return await DatabaseHelper.Count({ table: USER_TABLE, where: { ID: userID, password: crypt_pass } }) > 0; } /** * Crypt a password * * @param pass The password to crypt * @return Encrypted string */ private static CryptPassword(pass: string) : string { return crypt(sha1(pass), sha1(pass)); } private static DBToUserTokens(row : any) : UserLoginTokens { return { userID: row.user_id, clientID: row.service_id, token1: row.token1, token2: row.token2 }; } /** * Check out whether an email address exists or not * * @param email Email address to check */ public static async ExistsEmail(email: string) : Promise { return await DatabaseHelper.Count({ table: USER_TABLE, where: { mail: email } }) > 0; } /** * Find user ID from its email address * * @param email Email address * @returns The ID of the matching user / -1 if none found */ public static async FindIDFromEmail(email: string) : Promise { const result = await DatabaseHelper.QueryRow({ table: USER_TABLE, where: { mail: email, }, fields: ["ID"] }); return result == null ? -1 : result.ID; } /** * Check out whether a virtual directory is available or not * * @param dir Virtual directory to check * @param userID Target user ID */ public static async CheckUserDirectoryAvailability(dir: string, userID: number = -1) : Promise { const foundUser = await UserHelper.FindByFolder(dir); return foundUser < 1 || userID == foundUser; } /** * Generate a new token to reset an account password * * @param userID Target user ID * @returns Generated token */ public static async GenerateNewPasswordResetToken(userID: number) : Promise { // Generate a token const token = randomStr(255); await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: userID }, set: { password_reset_token: token, password_reset_token_time_create: time() } }); return token; } /** * Destroy password reset token for a given user * * @param userID Target user ID */ public static async DestroyPasswordResetTokenForUser(userID: number) { await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: userID }, set: { password_reset_token: "", password_reset_token_time_create: 85 // Value too low to be valid } }); } /** * Get the ID of a user from a password reset token * * @param token The token to use * @returns The ID of the user associated to the token, if it is valid / -1 else */ public static async GetUserIDFromPasswordResetToken(token: string) : Promise { // Query the database const result = await DatabaseHelper.QueryRow({ table: USER_TABLE, where: { password_reset_token: token, }, customWhere: "password_reset_token_time_create > ?", customWhereArgs:[(time()-60*60*24).toString()] // Tokens are valid for 24 hours }); if(result == null) return -1; return result.ID; } /** * Change the password of the user * * @param userID Target user ID * @param password Target password */ public static async ChangePassword(userID: number, password: string) { await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: userID }, set: { password: this.CryptPassword(password) } }); } /** * Set (save) new general settings * * @param settings New settings */ public static async SetGeneral(settings: GeneralSettings) { await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: settings.id }, set: { prenom: settings.firstName, nom: settings.lastName, public: settings.pageStatus != UserPageStatus.PRIVATE ? 1 : 0, pageouverte: settings.pageStatus == UserPageStatus.OPEN ? 1 : 0, bloquecommentaire: settings.blockComments ? 1 : 0, autoriser_post_amis: settings.allowPostsFromFriends ? 1 : 0, autorise_mail: settings.allowMails ? 1 : 0, liste_amis_publique: settings.friendsListPublic ? 1 : 0, sous_repertoire: settings.virtualDirectory, site_web: settings.personnalWebsite, public_note: settings.publicNote } }); } /** * Set (save) new language settings * * @param settings New settings */ public static async SetLanguageSettings(settings: LangSettings) { await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: settings.id }, set: { lang: settings.lang } }); } /** * Update (set) new security settings * * @param settings New settings */ public static async SetSecuritySettings(settings: SecuritySettings) { await DatabaseHelper.UpdateRows({ table: USER_TABLE, where: { ID: settings.id }, set: { question1: settings.security_question_1, reponse1: settings.security_answer_1, question2: settings.security_question_2, reponse2: settings.security_answer_2 } }); } /** * Export all the data of an account * * @param userID Target user ID */ public static async Export(userID: number) : Promise { const data = new AccountExport({ // General info userID: userID, userInfo: await UserHelper.GetUserInfo(userID), // Export the list of posts postsList: await PostsHelper.ExportAllPostsUser(userID), // Export the list of comments comments: await CommentsHelper.ExportAllUser(userID), // Export user likes likes: await LikesHelper.ExportAllUser(userID), // Export all responses of user to surveys surveyResponses: await SurveyHelper.ExportAllUserResponses(userID), // User movies movies: await MoviesHelper.GetListUser(userID), // Conversation messages conversationMessages: await ConversationsHelper.ExportAllMessages(userID), // Conversations list conversations: await ConversationsHelper.GetListUser(userID), }) // TODO : continue return data; } }