1
0
mirror of https://gitlab.com/comunic/comunicapiv2 synced 2024-11-26 15:29:22 +00:00
comunicapiv2/src/helpers/AccountHelper.ts

437 lines
10 KiB
TypeScript

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";
import { FriendsHelper } from "./FriendsHelper";
import { GroupsHelper } from "./GroupsHelper";
/**
* 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<UserLoginTokens | null> {
// 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<UserLoginTokens | null> {
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<number> {
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<boolean> {
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<boolean> {
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<number> {
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<boolean> {
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<string> {
// 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<number> {
// 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<AccountExport> {
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
allConversationMessages: await ConversationsHelper.ExportAllMessages(userID),
// Conversations list
conversations: await ConversationsHelper.GetListUser(userID),
// Conversations messages (completed after)
conversationsMessages: new Map(),
// Friends
friendsList: await FriendsHelper.GetList(userID),
// Groups membership
groups: await GroupsHelper.GetListUser(userID),
})
// Process conversation messages
for(const conv of data.conversations) {
data.conversationsMessages[conv.id]
= await ConversationsHelper.GetAllMessages(conv.id);
}
return data;
}
}