mirror of
https://gitlab.com/comunic/comunicapiv2
synced 2024-11-22 21:39:22 +00:00
535 lines
13 KiB
TypeScript
535 lines
13 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, LikesType } from "./LikesHelper";
|
|
import { SurveyHelper } from "./SurveyHelper";
|
|
import { MoviesHelper } from "./MoviesHelper";
|
|
import { ConversationsHelper } from "./ConversationsHelper";
|
|
import { FriendsHelper } from "./FriendsHelper";
|
|
import { GroupsHelper } from "./GroupsHelper";
|
|
import { NotificationsHelper } from "./NotificationsHelper";
|
|
import { AccountImageHelper } from "./AccountImageHelper";
|
|
import { BackgroundImageHelper } from "./BackgroundImageHelper";
|
|
import { EventsHelper } from "./EventsHelper";
|
|
|
|
/**
|
|
* 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) {
|
|
|
|
// Push the event
|
|
EventsHelper.Emit("destroyed_login_tokens", {
|
|
client: client,
|
|
userID: userID
|
|
});
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Update the last activity time of the user
|
|
*
|
|
* @param userID Target user ID
|
|
*/
|
|
public static async UpdateLastActivity(userID: number) {
|
|
await DatabaseHelper.UpdateRows({
|
|
table: USER_TABLE,
|
|
where: {
|
|
ID: userID
|
|
},
|
|
set: {
|
|
last_activity: time()
|
|
}
|
|
})
|
|
}
|
|
|
|
|
|
/**
|
|
* 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
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Delete all user login tokens
|
|
*
|
|
* This method has for immediate effect to disconnect
|
|
* the user from all its devices
|
|
*
|
|
* @param userID Target user ID
|
|
*/
|
|
public static async DeleteAllUserLoginTokens(userID: number) {
|
|
await DatabaseHelper.DeleteRows(USERS_TOKENS_TABLE, {
|
|
user_id: userID
|
|
})
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
* Remove completely a user account
|
|
*
|
|
* @param userID Target user ID
|
|
*/
|
|
public static async Delete(userID: number) {
|
|
|
|
/*// Delete all groups memberships
|
|
await GroupsHelper.DeleteAllUsersGroups(userID);
|
|
|
|
// Delete all user comments
|
|
await CommentsHelper.DeleteAllUser(userID);
|
|
|
|
// Delete all user posts
|
|
await PostsHelper.DeleteAllUser(userID);
|
|
|
|
// Delete all responses of user to surveys
|
|
await SurveyHelper.DeleteAllUserResponses(userID);
|
|
|
|
// Delete all the likes created by the user
|
|
await LikesHelper.DeleteAllUser(userID);
|
|
|
|
// Delete all user movies
|
|
await MoviesHelper.DeleteAllUser(userID);
|
|
|
|
// Delete conversation messages
|
|
await ConversationsHelper.DeleteAllUserMessages(userID);
|
|
|
|
// Remove the user from all its conversations
|
|
await ConversationsHelper.DeleteAllUserConversations(userID);
|
|
|
|
// Delete all the notifications related with the user
|
|
await NotificationsHelper.DeleteAllRelatedWithUser(userID);
|
|
|
|
// Delete all user friends, including friendship requests
|
|
await FriendsHelper.DeleteAllUser(userID);
|
|
|
|
// Delete user account image
|
|
await AccountImageHelper.Delete(userID);
|
|
|
|
// Delete all the likes on the user page
|
|
await LikesHelper.DeleteAll(userID, LikesType.USER);
|
|
|
|
// Delete user background image
|
|
await BackgroundImageHelper.Delete(userID);
|
|
|
|
// TODO : Delete custom user emojies
|
|
|
|
// Delete connections to all services
|
|
await this.DeleteAllUserLoginTokens(userID);
|
|
*/
|
|
|
|
// Delete user from the database
|
|
// WILL BE IMPLEMENTED LATER
|
|
}
|
|
} |