diff --git a/backend/app/Api/User/Session/Session.php b/backend/app/Api/User/Session/Session.php index b05d783..f624498 100755 --- a/backend/app/Api/User/Session/Session.php +++ b/backend/app/Api/User/Session/Session.php @@ -112,172 +112,172 @@ use MythicalClient\Chat\columns\UserColumns; $router->post('/api/user/session/info/update', function (): void { - App::init(); - $appInstance = App::getInstance(true); - $config = $appInstance->getConfig(); + App::init(); + $appInstance = App::getInstance(true); + $config = $appInstance->getConfig(); - $appInstance->allowOnlyPOST(); - $session = new Session($appInstance); + $appInstance->allowOnlyPOST(); + $session = new Session($appInstance); - try { - if (!isset($_POST['first_name']) && $_POST['first_name'] == '') { - $appInstance->BadRequest('First name is missing!', ['error_code' => 'FIRST_NAME_MISSING']); - } - if (!isset($_POST['last_name']) && $_POST['last_name'] == '') { - $appInstance->BadRequest('Last name is missing!', ['error_code' => 'LAST_NAME_MISSING']); - } - if (!isset($_POST['email']) && $_POST['email'] == '') { - $appInstance->BadRequest('Email is missing!', ['error_code' => 'EMAIL_MISSING']); - } - if (!isset($_POST['avatar']) && $_POST['avatar'] == '') { - $appInstance->BadRequest('Avatar is missing!', ['error_code' => 'AVATAR_MISSING']); - } - if (!isset($_POST['background']) && $_POST['background'] == '') { - $appInstance->BadRequest('Background is missing!', ['error_code' => 'BACKGROUND_MISSING']); - } + try { + if (!isset($_POST['first_name']) && $_POST['first_name'] == '') { + $appInstance->BadRequest('First name is missing!', ['error_code' => 'FIRST_NAME_MISSING']); + } + if (!isset($_POST['last_name']) && $_POST['last_name'] == '') { + $appInstance->BadRequest('Last name is missing!', ['error_code' => 'LAST_NAME_MISSING']); + } + if (!isset($_POST['email']) && $_POST['email'] == '') { + $appInstance->BadRequest('Email is missing!', ['error_code' => 'EMAIL_MISSING']); + } + if (!isset($_POST['avatar']) && $_POST['avatar'] == '') { + $appInstance->BadRequest('Avatar is missing!', ['error_code' => 'AVATAR_MISSING']); + } + if (!isset($_POST['background']) && $_POST['background'] == '') { + $appInstance->BadRequest('Background is missing!', ['error_code' => 'BACKGROUND_MISSING']); + } - if ($_POST['email'] != $session->getInfo(UserColumns::EMAIL, false) && User::exists(UserColumns::EMAIL, $_POST['email'])) { - $appInstance->BadRequest('Email already exists!', ['error_code' => 'EMAIL_EXISTS']); - } + if ($_POST['email'] != $session->getInfo(UserColumns::EMAIL, false) && User::exists(UserColumns::EMAIL, $_POST['email'])) { + $appInstance->BadRequest('Email already exists!', ['error_code' => 'EMAIL_EXISTS']); + } - $session->setInfo(UserColumns::FIRST_NAME, $_POST['first_name'], true); - $session->setInfo(UserColumns::LAST_NAME, $_POST['last_name'], true); - $session->setInfo(UserColumns::EMAIL, $_POST['email'], false); - $session->setInfo(UserColumns::AVATAR, $_POST['avatar'], false); - $session->setInfo(UserColumns::BACKGROUND, $_POST['background'], false); + $session->setInfo(UserColumns::FIRST_NAME, $_POST['first_name'], true); + $session->setInfo(UserColumns::LAST_NAME, $_POST['last_name'], true); + $session->setInfo(UserColumns::EMAIL, $_POST['email'], false); + $session->setInfo(UserColumns::AVATAR, $_POST['avatar'], false); + $session->setInfo(UserColumns::BACKGROUND, $_POST['background'], false); - $appInstance->OK('User info updated successfully!', []); - } catch (Exception $e) { - $appInstance->getLogger()->error('Failed to update user info! ' . $e->getMessage()); - $appInstance->BadRequest('Bad Request', ['error_code' => 'DB_ERROR', 'error' => $e->getMessage()]); - } + $appInstance->OK('User info updated successfully!', []); + } catch (Exception $e) { + $appInstance->getLogger()->error('Failed to update user info! ' . $e->getMessage()); + $appInstance->BadRequest('Bad Request', ['error_code' => 'DB_ERROR', 'error' => $e->getMessage()]); + } }); $router->post('/api/user/session/billing/update', function (): void { - App::init(); - $appInstance = App::getInstance(true); - $config = $appInstance->getConfig(); + App::init(); + $appInstance = App::getInstance(true); + $config = $appInstance->getConfig(); - $appInstance->allowOnlyPOST(); - $session = new Session($appInstance); + $appInstance->allowOnlyPOST(); + $session = new Session($appInstance); - try { - if (!isset($_POST['company_name']) && $_POST['company_name'] == '') { - $appInstance->BadRequest('Company name is missing!', ['error_code' => 'COMPANY_NAME_MISSING']); - } - $companyName = $_POST['company_name']; - if (!isset($_POST['vat_number']) && $_POST['vat_number'] == '') { - $appInstance->BadRequest('VAT Number is missing!', ['error_code' => 'VAT_NUMBER_MISSING']); - } - $vatNumber = $_POST['vat_number']; - if (!isset($_POST['address1']) && $_POST['address1'] == '') { - $appInstance->BadRequest('Address 1 is missing', ['error_code' => 'ADDRESS1_MISSING']); - } - $address1 = $_POST['address1']; - if (!isset($_POST['address2']) && $_POST['address2'] == '') { - $appInstance->BadRequest('Address 2 is missing', ['error_code' => 'ADDRESS2_MISSING']); - } - $address2 = $_POST['address2']; - if (!isset($_POST['city']) && $_POST['city'] == '') { - $appInstance->BadRequest('City is missing', ['error_code' => 'CITY_MISSING']); - } - $city = $_POST['city']; - if (!isset($_POST['country']) && $_POST['country'] == '') { - $appInstance->BadRequest('Country is missing', ['error_code' => 'COUNTRY_MISSING']); - } - $country = $_POST['country']; - if (!isset($_POST['state']) && $_POST['state'] == '') { - $appInstance->BadRequest('State is missing', ['error_code' => 'STATE_MISSING']); - } - $state = $_POST['state']; - if (!isset($_POST['postcode']) && $_POST['postcode'] == '') { - $appInstance->BadRequest('PostCode is missing', ['error_code' => 'POSTCODE_MISSING']); - } - $postcode = $_POST['postcode']; + try { + if (!isset($_POST['company_name']) && $_POST['company_name'] == '') { + $appInstance->BadRequest('Company name is missing!', ['error_code' => 'COMPANY_NAME_MISSING']); + } + $companyName = $_POST['company_name']; + if (!isset($_POST['vat_number']) && $_POST['vat_number'] == '') { + $appInstance->BadRequest('VAT Number is missing!', ['error_code' => 'VAT_NUMBER_MISSING']); + } + $vatNumber = $_POST['vat_number']; + if (!isset($_POST['address1']) && $_POST['address1'] == '') { + $appInstance->BadRequest('Address 1 is missing', ['error_code' => 'ADDRESS1_MISSING']); + } + $address1 = $_POST['address1']; + if (!isset($_POST['address2']) && $_POST['address2'] == '') { + $appInstance->BadRequest('Address 2 is missing', ['error_code' => 'ADDRESS2_MISSING']); + } + $address2 = $_POST['address2']; + if (!isset($_POST['city']) && $_POST['city'] == '') { + $appInstance->BadRequest('City is missing', ['error_code' => 'CITY_MISSING']); + } + $city = $_POST['city']; + if (!isset($_POST['country']) && $_POST['country'] == '') { + $appInstance->BadRequest('Country is missing', ['error_code' => 'COUNTRY_MISSING']); + } + $country = $_POST['country']; + if (!isset($_POST['state']) && $_POST['state'] == '') { + $appInstance->BadRequest('State is missing', ['error_code' => 'STATE_MISSING']); + } + $state = $_POST['state']; + if (!isset($_POST['postcode']) && $_POST['postcode'] == '') { + $appInstance->BadRequest('PostCode is missing', ['error_code' => 'POSTCODE_MISSING']); + } + $postcode = $_POST['postcode']; - Billing::updateBilling( - $session->getInfo(UserColumns::UUID, false), - $companyName, - $vatNumber, - $address1, - $address2, - $city, - $country, - $state, - $postcode - ); + Billing::updateBilling( + $session->getInfo(UserColumns::UUID, false), + $companyName, + $vatNumber, + $address1, + $address2, + $city, + $country, + $state, + $postcode + ); - $appInstance->OK('Billing info saved successfully!', []); - } catch (Exception $e) { - $appInstance->getLogger()->error('Failed to save billing info! ' . $e->getMessage()); - $appInstance->BadRequest('Bad Request', ['error_code' => 'DB_ERROR', 'error' => $e->getMessage()]); - } + $appInstance->OK('Billing info saved successfully!', []); + } catch (Exception $e) { + $appInstance->getLogger()->error('Failed to save billing info! ' . $e->getMessage()); + $appInstance->BadRequest('Bad Request', ['error_code' => 'DB_ERROR', 'error' => $e->getMessage()]); + } }); $router->get('/api/user/session', function (): void { - App::init(); - $appInstance = App::getInstance(true); - $config = $appInstance->getConfig(); + App::init(); + $appInstance = App::getInstance(true); + $config = $appInstance->getConfig(); - $appInstance->allowOnlyGET(); + $appInstance->allowOnlyGET(); - $session = new Session($appInstance); + $session = new Session($appInstance); - $accountToken = $session->SESSION_KEY; - try { - $billing = Billing::getBillingData(User::getInfo($accountToken, UserColumns::UUID, false)); - $columns = [ - UserColumns::USERNAME, - UserColumns::EMAIL, - UserColumns::VERIFIED, - UserColumns::BANNED, - UserColumns::TWO_FA_BLOCKED, - UserColumns::TWO_FA_ENABLED, - UserColumns::TWO_FA_KEY, - UserColumns::FIRST_NAME, - UserColumns::LAST_NAME, - UserColumns::AVATAR, - UserColumns::UUID, - UserColumns::ROLE_ID, - UserColumns::FIRST_IP, - UserColumns::LAST_IP, - UserColumns::DELETED, - UserColumns::LAST_SEEN, - UserColumns::FIRST_SEEN, - UserColumns::BACKGROUND - ]; + $accountToken = $session->SESSION_KEY; + try { + $billing = Billing::getBillingData(User::getInfo($accountToken, UserColumns::UUID, false)); + $columns = [ + UserColumns::USERNAME, + UserColumns::EMAIL, + UserColumns::VERIFIED, + UserColumns::BANNED, + UserColumns::TWO_FA_BLOCKED, + UserColumns::TWO_FA_ENABLED, + UserColumns::TWO_FA_KEY, + UserColumns::FIRST_NAME, + UserColumns::LAST_NAME, + UserColumns::AVATAR, + UserColumns::UUID, + UserColumns::ROLE_ID, + UserColumns::FIRST_IP, + UserColumns::LAST_IP, + UserColumns::DELETED, + UserColumns::LAST_SEEN, + UserColumns::FIRST_SEEN, + UserColumns::BACKGROUND, + ]; - $info = User::getInfoArray($accountToken, $columns, [ - UserColumns::FIRST_NAME, - UserColumns::LAST_NAME, - UserColumns::TWO_FA_KEY, - ]); - $info['role_name'] = Roles::getUserRoleName($info[UserColumns::UUID]); - $info['role_real_name'] = strtolower($info['role_name']); + $info = User::getInfoArray($accountToken, $columns, [ + UserColumns::FIRST_NAME, + UserColumns::LAST_NAME, + UserColumns::TWO_FA_KEY, + ]); + $info['role_name'] = Roles::getUserRoleName($info[UserColumns::UUID]); + $info['role_real_name'] = strtolower($info['role_name']); - $appInstance->OK('Account token is valid', [ - 'user_info' => $info, - 'billing' => $billing, - ]); + $appInstance->OK('Account token is valid', [ + 'user_info' => $info, + 'billing' => $billing, + ]); - } catch (Exception $e) { - $appInstance->BadRequest('Bad Request', ['error_code' => 'INVALID_ACCOUNT_TOKEN', 'error' => $e->getMessage()]); - } + } catch (Exception $e) { + $appInstance->BadRequest('Bad Request', ['error_code' => 'INVALID_ACCOUNT_TOKEN', 'error' => $e->getMessage()]); + } }); $router->get('/api/user/session/activities', function (): void { - App::init(); - $appInstance = App::getInstance(true); - $config = $appInstance->getConfig(); + App::init(); + $appInstance = App::getInstance(true); + $config = $appInstance->getConfig(); - $appInstance->allowOnlyGET(); + $appInstance->allowOnlyGET(); - $session = new Session($appInstance); + $session = new Session($appInstance); - $accountToken = $session->SESSION_KEY; + $accountToken = $session->SESSION_KEY; - $appInstance->OK('User activities', [ - 'activities' => UserActivities::get(User::getInfo($accountToken, UserColumns::UUID, false)), - ]); + $appInstance->OK('User activities', [ + 'activities' => UserActivities::get(User::getInfo($accountToken, UserColumns::UUID, false)), + ]); }); diff --git a/backend/app/App.php b/backend/app/App.php index 873ccbb..36e0097 100755 --- a/backend/app/App.php +++ b/backend/app/App.php @@ -105,16 +105,16 @@ namespace MythicalClient; -use MythicalClient\CloudFlare\CloudFlareRealIP; -use RateLimit\Exception\LimitExceeded; use RateLimit\Rate; -use RateLimit\RedisRateLimiter; use Router\Router as rt; +use RateLimit\RedisRateLimiter; use MythicalClient\Chat\Database; use MythicalSystems\Utils\XChaCha20; use MythicalClient\Hooks\MythicalAPP; +use RateLimit\Exception\LimitExceeded; use MythicalClient\Config\ConfigFactory; use MythicalClient\Logger\LoggerFactory; +use MythicalClient\CloudFlare\CloudFlareRealIP; class App extends MythicalAPP { @@ -146,32 +146,32 @@ public function __construct(bool $softBoot) return; } - /** - * Redis. - */ - $redis = new FastChat\Redis(); - if ($redis->testConnection() == false) { - define('REDIS_ENABLED', false); - } else { - define('REDIS_ENABLED', true); - } - - // @phpstan-ignore-next-line - $rateLimiter = new RedisRateLimiter(Rate::perMinute(RATE_LIMIT), new \Redis(), "rate_limiting"); - try { - $rateLimiter->limit(CloudFlareRealIP::getRealIP()); - } catch (LimitExceeded $e) { - self::getLogger()->error('User: '. $e->getMessage()); - self::init(); - self::ServiceUnavailable('You are being rate limited!', ['error_code' => 'RATE_LIMITED']); - } catch (\Exception $e) { - self::getLogger()->error("-----------------------------"); - self::getLogger()->error("REDIS SERVER IS DOWN"); - self::getLogger()->error("RATE LIMITING IS DISABLED"); - self::getLogger()->error("YOU SHOULD FIX THIS ASAP"); - self::getLogger()->error("NO SUPPORT WILL BE PROVIDED"); - self::getLogger()->error("-----------------------------"); - } + /** + * Redis. + */ + $redis = new FastChat\Redis(); + if ($redis->testConnection() == false) { + define('REDIS_ENABLED', false); + } else { + define('REDIS_ENABLED', true); + } + + // @phpstan-ignore-next-line + $rateLimiter = new RedisRateLimiter(Rate::perMinute(RATE_LIMIT), new \Redis(), 'rate_limiting'); + try { + $rateLimiter->limit(CloudFlareRealIP::getRealIP()); + } catch (LimitExceeded $e) { + self::getLogger()->error('User: ' . $e->getMessage()); + self::init(); + self::ServiceUnavailable('You are being rate limited!', ['error_code' => 'RATE_LIMITED']); + } catch (\Exception $e) { + self::getLogger()->error('-----------------------------'); + self::getLogger()->error('REDIS SERVER IS DOWN'); + self::getLogger()->error('RATE LIMITING IS DISABLED'); + self::getLogger()->error('YOU SHOULD FIX THIS ASAP'); + self::getLogger()->error('NO SUPPORT WILL BE PROVIDED'); + self::getLogger()->error('-----------------------------'); + } /** * Database Connection. diff --git a/backend/app/Chat/User.php b/backend/app/Chat/User.php index 921d218..95df370 100755 --- a/backend/app/Chat/User.php +++ b/backend/app/Chat/User.php @@ -118,359 +118,359 @@ class User extends Database { - public const TABLE_NAME = 'mythicalclient_users'; - - /** - * Register a new user in the database. - * - * @param string $username The username of the user - * @param string $password The password of the user - * @param string $email The email of the user - * @param string $first_name The first name of the user - * @param string $last_name The last name of the user - * @param string $ip The ip of the user - * - * @return string - */ - public static function register(string $username, string $password, string $email, string $first_name, string $last_name, string $ip): void - { - try { - $first_name = App::getInstance(true)->encrypt($first_name); - $last_name = App::getInstance(true)->encrypt($last_name); - - /** - * The UUID generation and logic. - */ - $uuidMngr = new \MythicalSystems\User\UUIDManager(); - $uuid = $uuidMngr->generateUUID(); - $token = App::getInstance(true)->encrypt(date('Y-m-d H:i:s') . $uuid . random_bytes(16) . base64_encode($email)); - - /** - * GRAvatar Logic. - */ - try { - $gravatar = new Gravatar(['s' => 9001], true); - $avatar = $gravatar->avatar($email); - } catch (\Exception) { - $avatar = 'https://www.gravatar.com/avatar'; - } - - /** - * Get the PDO connection. - */ - $pdoConnection = self::getPdoConnection(); - - /** - * Prepare the statement. - */ - $stmt = $pdoConnection->prepare(' + public const TABLE_NAME = 'mythicalclient_users'; + + /** + * Register a new user in the database. + * + * @param string $username The username of the user + * @param string $password The password of the user + * @param string $email The email of the user + * @param string $first_name The first name of the user + * @param string $last_name The last name of the user + * @param string $ip The ip of the user + * + * @return string + */ + public static function register(string $username, string $password, string $email, string $first_name, string $last_name, string $ip): void + { + try { + $first_name = App::getInstance(true)->encrypt($first_name); + $last_name = App::getInstance(true)->encrypt($last_name); + + /** + * The UUID generation and logic. + */ + $uuidMngr = new \MythicalSystems\User\UUIDManager(); + $uuid = $uuidMngr->generateUUID(); + $token = App::getInstance(true)->encrypt(date('Y-m-d H:i:s') . $uuid . random_bytes(16) . base64_encode($email)); + + /** + * GRAvatar Logic. + */ + try { + $gravatar = new Gravatar(['s' => 9001], true); + $avatar = $gravatar->avatar($email); + } catch (\Exception) { + $avatar = 'https://www.gravatar.com/avatar'; + } + + /** + * Get the PDO connection. + */ + $pdoConnection = self::getPdoConnection(); + + /** + * Prepare the statement. + */ + $stmt = $pdoConnection->prepare(' INSERT INTO ' . self::TABLE_NAME . ' (username, first_name, last_name, email, password, avatar, background, uuid, token, role, first_ip, last_ip, banned, verified) VALUES (:username, :first_name, :last_name, :email, :password, :avatar, :background, :uuid, :token, :role, :first_ip, :last_ip, :banned, :verified) '); - $password = App::getInstance(true)->encrypt($password); - - $stmt->execute([ - ':username' => $username, - ':first_name' => $first_name, - ':last_name' => $last_name, - ':email' => $email, - ':password' => $password, - ':avatar' => $avatar, - ':background' => 'https://cdn.mythicalsystems.xyz/background.gif', - ':uuid' => $uuid, - ':token' => $token, - ':role' => 1, - ':first_ip' => $ip, - ':last_ip' => $ip, - ':banned' => 'NO', - ':verified' => 'false', - ]); - \MythicalClient\MythicalSystems\Telemetry::send(\MythicalClient\MythicalSystems\TelemetryCollection::USER_NEW); - /** - * Check if the mail is enabled. - * - * If it is, the user is not verified. - * - * If it is not, the user is verified. - */ - if (Mail::isEnabled()) { - try { - $verify_token = App::getInstance(true)->generateCode(); - Verification::add($verify_token, $uuid, EmailVerificationColumns::$type_verify); - Verify::sendMail($uuid, $verify_token); - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); - self::updateInfo($token, UserColumns::VERIFIED, 'false', false); - } - } else { - self::updateInfo($token, UserColumns::VERIFIED, 'true', false); - } - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to register user: ' . $e->getMessage()); - throw new \Exception('Failed to register user: ' . $e->getMessage()); - } - } - - /** - * Get the list of users. - * - * @return array The list of users - */ - public static function getList(): array - { - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT * FROM ' . self::TABLE_NAME); - $stmt->execute(); - - return $stmt->fetchAll(\PDO::FETCH_ASSOC); - } - - /** - * Forgot password logic. - * - * @param string $email The email of the user - * - * @return bool If the email was sent - */ - public static function forgotPassword(string $email): bool - { - try { - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT token, uuid FROM ' . self::TABLE_NAME . ' WHERE email = :email'); - $stmt->bindParam(':email', $email); - $stmt->execute(); - $user = $stmt->fetch(\PDO::FETCH_ASSOC); - - if ($user) { - if (Mail::isEnabled()) { - try { - $verify_token = $verify_token = App::getInstance(true)->generateCode(); - Verification::add($verify_token, $user['uuid'], EmailVerificationColumns::$type_password); - ResetPassword::sendMail($user['uuid'], $verify_token); - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); - } - - return true; - } - - return false; - } - - return false; - } catch (\Exception $e) { - return false; - } - } - - /** - * Login the user. - * - * @param string $login The login of the user - * @param string $password The password of the user - * - * @return string If the login was successful - */ - public static function login(string $login, string $password): string - { - try { - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT password, token, uuid FROM ' . self::TABLE_NAME . ' WHERE username = :login OR email = :login'); - $stmt->bindParam(':login', $login); - $stmt->execute(); - $user = $stmt->fetch(\PDO::FETCH_ASSOC); - if ($user) { - if (App::getInstance(true)->decrypt($user['password']) == $password) { - self::logout(); - if (!$user['token'] == '') { - setcookie('user_token', $user['token'], time() + 3600, '/'); - } else { - App::getInstance(true)->getLogger()->error('Failed to login user: Token is empty'); - - return 'false'; - } - if (Mail::isEnabled()) { - try { - NewLogin::sendMail($user['uuid']); - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); - } - } - UserActivities::add($user['uuid'], UserActivitiesTypes::$login, CloudFlare::getRealUserIP()); - - return $user['token']; - } - - return 'false'; - } - - return 'false'; - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to login user: ' . $e->getMessage()); - - return 'false'; - } - } - - /** - * Logout the user. - */ - public static function logout(): void - { - setcookie('user_token', '', time() - 460800 * 460800 * 460800, '/'); - } - - /** - * Does the user info exist? - * - * @param UserColumns $info - */ - public static function exists(UserColumns|string $info, string $value): bool - { - if (!in_array($info, UserColumns::getColumns())) { - throw new \InvalidArgumentException('Invalid column name: ' . $info); - } - - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT * FROM ' . self::TABLE_NAME . ' WHERE ' . $info . ' = :value'); - $stmt->bindParam(':value', $value); - $stmt->execute(); - - return (bool) $stmt->fetchColumn(); - } - - /** - * Get the user info. - * - * @param UserColumns|string $info The column name - * - * @throws \InvalidArgumentException If the column name is invalid - * - * @return string|null The value of the column - */ - public static function getInfo(string $token, UserColumns|string $info, bool $encrypted): ?string - { - if (!in_array($info, UserColumns::getColumns())) { - throw new \InvalidArgumentException('Invalid column name: ' . $info); - } - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT ' . $info . ' FROM ' . self::TABLE_NAME . ' WHERE token = :token'); - $stmt->bindParam(':token', $token); - $stmt->execute(); - if ($encrypted) { - return App::getInstance(true)->decrypt($stmt->fetchColumn()); - } - - return $stmt->fetchColumn(); - - } - /** - * Get the user info. - * - * @param string $token The token - * - * @return array The user info - */ - public static function getInfoArray(string $token, array $columns, array $columns_encrypted): array - { - $con = self::getPdoConnection(); - $columns_str = implode(', ', $columns); - $stmt = $con->prepare('SELECT ' . $columns_str . ' FROM ' . self::TABLE_NAME . ' WHERE token = :token'); - $stmt->bindParam(':token', $token); - $stmt->execute(); - - $result = $stmt->fetch(\PDO::FETCH_ASSOC); - - foreach ($columns as $index => $column) { - if (in_array($column, $columns_encrypted)) { - $result[$column] = App::getInstance(true)->decrypt($result[$column]); - } - } - - return $result ? $result : []; - } - - - /** - * Update the user info. - * - * @param UserColumns|string $info The column name - * @param string $value The value to update - * @param bool $encrypted If the value is encrypted - * - * @throws \InvalidArgumentException If the column name is invalid - * - * @return bool If the update was successful - */ - public static function updateInfo(string $token, UserColumns|string $info, string $value, bool $encrypted): bool - { - if (!in_array($info, UserColumns::getColumns())) { - throw new \InvalidArgumentException('Invalid column name: ' . $info); - } - $con = self::getPdoConnection(); - if ($encrypted) { - $value = App::getInstance(true)->encrypt($value); - } - $stmt = $con->prepare('UPDATE ' . self::TABLE_NAME . ' SET ' . $info . ' = :value WHERE token = :token'); - $stmt->bindParam(':value', $value); - $stmt->bindParam(':token', $token); - - return $stmt->execute(); - } - - /** - * Get the token from the UUID. - * - * @param string $uuid The UUID - * - * @return string The token - */ - public static function getTokenFromUUID(string $uuid): string - { - $con = self::getPdoConnection(); - $stmt = $con->prepare('SELECT token FROM ' . self::TABLE_NAME . ' WHERE uuid = :uuid'); - $stmt->bindParam(':uuid', $uuid); - $stmt->execute(); - - return $stmt->fetchColumn(); - } - - /** - * Process the template. - * - * @param string $template The template - * @param string $uuid The UUID - * - * @return string The processed template - */ - public static function processTemplate(string $template, string $uuid): string - { - try { - - $template = str_replace('${uuid}', $uuid, $template); - $template = str_replace('${username}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::USERNAME, false), $template); - $template = str_replace('${email}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::EMAIL, false), $template); - $template = str_replace('${first_name}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_NAME, true), $template); - $template = str_replace('${last_name}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_NAME, true), $template); - $template = str_replace('${avatar}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::AVATAR, false), $template); - $template = str_replace('${background}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::BACKGROUND, false), $template); - $template = str_replace('${role_id}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::ROLE_ID, false), $template); - $template = str_replace('${first_ip}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_IP, false), $template); - $template = str_replace('${last_ip}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_IP, false), $template); - $template = str_replace('${banned}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::BANNED, false), $template); - $template = str_replace('${verified}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::VERIFIED, false), $template); - $template = str_replace('${2fa_enabled}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::TWO_FA_ENABLED, false), $template); - $template = str_replace('${deleted}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::DELETED, false), $template); - $template = str_replace('${last_seen}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_SEEN, false), $template); - $template = str_replace('${first_seen}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_SEEN, false), $template); - - return $template; - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to render email template: ' . $e->getMessage()); - - return null; - } - } + $password = App::getInstance(true)->encrypt($password); + + $stmt->execute([ + ':username' => $username, + ':first_name' => $first_name, + ':last_name' => $last_name, + ':email' => $email, + ':password' => $password, + ':avatar' => $avatar, + ':background' => 'https://cdn.mythicalsystems.xyz/background.gif', + ':uuid' => $uuid, + ':token' => $token, + ':role' => 1, + ':first_ip' => $ip, + ':last_ip' => $ip, + ':banned' => 'NO', + ':verified' => 'false', + ]); + \MythicalClient\MythicalSystems\Telemetry::send(\MythicalClient\MythicalSystems\TelemetryCollection::USER_NEW); + /** + * Check if the mail is enabled. + * + * If it is, the user is not verified. + * + * If it is not, the user is verified. + */ + if (Mail::isEnabled()) { + try { + $verify_token = App::getInstance(true)->generateCode(); + Verification::add($verify_token, $uuid, EmailVerificationColumns::$type_verify); + Verify::sendMail($uuid, $verify_token); + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); + self::updateInfo($token, UserColumns::VERIFIED, 'false', false); + } + } else { + self::updateInfo($token, UserColumns::VERIFIED, 'true', false); + } + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to register user: ' . $e->getMessage()); + throw new \Exception('Failed to register user: ' . $e->getMessage()); + } + } + + /** + * Get the list of users. + * + * @return array The list of users + */ + public static function getList(): array + { + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT * FROM ' . self::TABLE_NAME); + $stmt->execute(); + + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } + + /** + * Forgot password logic. + * + * @param string $email The email of the user + * + * @return bool If the email was sent + */ + public static function forgotPassword(string $email): bool + { + try { + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT token, uuid FROM ' . self::TABLE_NAME . ' WHERE email = :email'); + $stmt->bindParam(':email', $email); + $stmt->execute(); + $user = $stmt->fetch(\PDO::FETCH_ASSOC); + + if ($user) { + if (Mail::isEnabled()) { + try { + $verify_token = $verify_token = App::getInstance(true)->generateCode(); + Verification::add($verify_token, $user['uuid'], EmailVerificationColumns::$type_password); + ResetPassword::sendMail($user['uuid'], $verify_token); + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); + } + + return true; + } + + return false; + } + + return false; + } catch (\Exception $e) { + return false; + } + } + + /** + * Login the user. + * + * @param string $login The login of the user + * @param string $password The password of the user + * + * @return string If the login was successful + */ + public static function login(string $login, string $password): string + { + try { + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT password, token, uuid FROM ' . self::TABLE_NAME . ' WHERE username = :login OR email = :login'); + $stmt->bindParam(':login', $login); + $stmt->execute(); + $user = $stmt->fetch(\PDO::FETCH_ASSOC); + if ($user) { + if (App::getInstance(true)->decrypt($user['password']) == $password) { + self::logout(); + if (!$user['token'] == '') { + setcookie('user_token', $user['token'], time() + 3600, '/'); + } else { + App::getInstance(true)->getLogger()->error('Failed to login user: Token is empty'); + + return 'false'; + } + if (Mail::isEnabled()) { + try { + NewLogin::sendMail($user['uuid']); + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); + } + } + UserActivities::add($user['uuid'], UserActivitiesTypes::$login, CloudFlare::getRealUserIP()); + + return $user['token']; + } + + return 'false'; + } + + return 'false'; + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to login user: ' . $e->getMessage()); + + return 'false'; + } + } + + /** + * Logout the user. + */ + public static function logout(): void + { + setcookie('user_token', '', time() - 460800 * 460800 * 460800, '/'); + } + + /** + * Does the user info exist? + * + * @param UserColumns $info + */ + public static function exists(UserColumns|string $info, string $value): bool + { + if (!in_array($info, UserColumns::getColumns())) { + throw new \InvalidArgumentException('Invalid column name: ' . $info); + } + + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT * FROM ' . self::TABLE_NAME . ' WHERE ' . $info . ' = :value'); + $stmt->bindParam(':value', $value); + $stmt->execute(); + + return (bool) $stmt->fetchColumn(); + } + + /** + * Get the user info. + * + * @param UserColumns|string $info The column name + * + * @throws \InvalidArgumentException If the column name is invalid + * + * @return string|null The value of the column + */ + public static function getInfo(string $token, UserColumns|string $info, bool $encrypted): ?string + { + if (!in_array($info, UserColumns::getColumns())) { + throw new \InvalidArgumentException('Invalid column name: ' . $info); + } + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT ' . $info . ' FROM ' . self::TABLE_NAME . ' WHERE token = :token'); + $stmt->bindParam(':token', $token); + $stmt->execute(); + if ($encrypted) { + return App::getInstance(true)->decrypt($stmt->fetchColumn()); + } + + return $stmt->fetchColumn(); + + } + + /** + * Get the user info. + * + * @param string $token The token + * + * @return array The user info + */ + public static function getInfoArray(string $token, array $columns, array $columns_encrypted): array + { + $con = self::getPdoConnection(); + $columns_str = implode(', ', $columns); + $stmt = $con->prepare('SELECT ' . $columns_str . ' FROM ' . self::TABLE_NAME . ' WHERE token = :token'); + $stmt->bindParam(':token', $token); + $stmt->execute(); + + $result = $stmt->fetch(\PDO::FETCH_ASSOC); + + foreach ($columns as $index => $column) { + if (in_array($column, $columns_encrypted)) { + $result[$column] = App::getInstance(true)->decrypt($result[$column]); + } + } + + return $result ? $result : []; + } + + /** + * Update the user info. + * + * @param UserColumns|string $info The column name + * @param string $value The value to update + * @param bool $encrypted If the value is encrypted + * + * @throws \InvalidArgumentException If the column name is invalid + * + * @return bool If the update was successful + */ + public static function updateInfo(string $token, UserColumns|string $info, string $value, bool $encrypted): bool + { + if (!in_array($info, UserColumns::getColumns())) { + throw new \InvalidArgumentException('Invalid column name: ' . $info); + } + $con = self::getPdoConnection(); + if ($encrypted) { + $value = App::getInstance(true)->encrypt($value); + } + $stmt = $con->prepare('UPDATE ' . self::TABLE_NAME . ' SET ' . $info . ' = :value WHERE token = :token'); + $stmt->bindParam(':value', $value); + $stmt->bindParam(':token', $token); + + return $stmt->execute(); + } + + /** + * Get the token from the UUID. + * + * @param string $uuid The UUID + * + * @return string The token + */ + public static function getTokenFromUUID(string $uuid): string + { + $con = self::getPdoConnection(); + $stmt = $con->prepare('SELECT token FROM ' . self::TABLE_NAME . ' WHERE uuid = :uuid'); + $stmt->bindParam(':uuid', $uuid); + $stmt->execute(); + + return $stmt->fetchColumn(); + } + + /** + * Process the template. + * + * @param string $template The template + * @param string $uuid The UUID + * + * @return string The processed template + */ + public static function processTemplate(string $template, string $uuid): string + { + try { + + $template = str_replace('${uuid}', $uuid, $template); + $template = str_replace('${username}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::USERNAME, false), $template); + $template = str_replace('${email}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::EMAIL, false), $template); + $template = str_replace('${first_name}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_NAME, true), $template); + $template = str_replace('${last_name}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_NAME, true), $template); + $template = str_replace('${avatar}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::AVATAR, false), $template); + $template = str_replace('${background}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::BACKGROUND, false), $template); + $template = str_replace('${role_id}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::ROLE_ID, false), $template); + $template = str_replace('${first_ip}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_IP, false), $template); + $template = str_replace('${last_ip}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_IP, false), $template); + $template = str_replace('${banned}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::BANNED, false), $template); + $template = str_replace('${verified}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::VERIFIED, false), $template); + $template = str_replace('${2fa_enabled}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::TWO_FA_ENABLED, false), $template); + $template = str_replace('${deleted}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::DELETED, false), $template); + $template = str_replace('${last_seen}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::LAST_SEEN, false), $template); + $template = str_replace('${first_seen}', self::getInfo(self::getTokenFromUUID($uuid), UserColumns::FIRST_SEEN, false), $template); + + return $template; + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to render email template: ' . $e->getMessage()); + + return null; + } + } } diff --git a/backend/app/Chat/UserActivities.php b/backend/app/Chat/UserActivities.php index db9745b..e00458e 100755 --- a/backend/app/Chat/UserActivities.php +++ b/backend/app/Chat/UserActivities.php @@ -109,71 +109,71 @@ class UserActivities { - /** - * Add user activity. - * - * @param string $uuid User UUID - * @param string|UserActivitiesTypes $type Activity type - * @param string $ipv4 IP address - */ - public static function add(string $uuid, string|UserActivitiesTypes $type, string $ipv4): bool - { - $dbConn = Database::getPdoConnection(); + /** + * Add user activity. + * + * @param string $uuid User UUID + * @param string|UserActivitiesTypes $type Activity type + * @param string $ipv4 IP address + */ + public static function add(string $uuid, string|UserActivitiesTypes $type, string $ipv4): bool + { + $dbConn = Database::getPdoConnection(); - $stmt = $dbConn->prepare('INSERT INTO ' . self::getTable() . ' (user, action, ip_address) VALUES (:user, :action, :ip_address)'); + $stmt = $dbConn->prepare('INSERT INTO ' . self::getTable() . ' (user, action, ip_address) VALUES (:user, :action, :ip_address)'); - return $stmt->execute([ - ':user' => $uuid, - ':action' => $type, - ':ip_address' => $ipv4, - ]); - } + return $stmt->execute([ + ':user' => $uuid, + ':action' => $type, + ':ip_address' => $ipv4, + ]); + } - /** - * Get user activities. - * - * @param string $uuid User UUID - */ - public static function get(string $uuid): array - { - $dbConn = Database::getPdoConnection(); + /** + * Get user activities. + * + * @param string $uuid User UUID + */ + public static function get(string $uuid): array + { + $dbConn = Database::getPdoConnection(); - $stmt = $dbConn->prepare('SELECT * FROM ' . self::getTable() . ' WHERE user = :user LIMIT 125'); - $stmt->execute([ - ':user' => $uuid, - ]); + $stmt = $dbConn->prepare('SELECT * FROM ' . self::getTable() . ' WHERE user = :user LIMIT 125'); + $stmt->execute([ + ':user' => $uuid, + ]); - return $stmt->fetchAll(\PDO::FETCH_ASSOC); - } + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } - /** - * Get all user activities. - * - * @param int $limit Limit - */ - public static function getAll(int $limit = 50): array - { - try { - $dbConn = Database::getPdoConnection(); + /** + * Get all user activities. + * + * @param int $limit Limit + */ + public static function getAll(int $limit = 50): array + { + try { + $dbConn = Database::getPdoConnection(); - $stmt = $dbConn->prepare('SELECT * FROM ' . self::getTable() . ' LIMIT ' . $limit); - $stmt->execute(); + $stmt = $dbConn->prepare('SELECT * FROM ' . self::getTable() . ' LIMIT ' . $limit); + $stmt->execute(); - return $stmt->fetchAll(\PDO::FETCH_ASSOC); - } catch (\Exception $e) { - Database::db_Error('Failed to get all user activities: ' . $e->getMessage()); + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + } catch (\Exception $e) { + Database::db_Error('Failed to get all user activities: ' . $e->getMessage()); - return []; - } - } + return []; + } + } - /** - * Get table name. - * - * @return string Table name - */ - public static function getTable(): string - { - return 'mythicalclient_users_activities'; - } + /** + * Get table name. + * + * @return string Table name + */ + public static function getTable(): string + { + return 'mythicalclient_users_activities'; + } } diff --git a/backend/app/Hooks/GitHub.php b/backend/app/Hooks/GitHub.php index 346fe36..8b858d6 100755 --- a/backend/app/Hooks/GitHub.php +++ b/backend/app/Hooks/GitHub.php @@ -105,46 +105,46 @@ namespace MythicalClient\Hooks; -use MythicalClient\Cache\Cache; use GuzzleHttp\Client; +use MythicalClient\Cache\Cache; class GitHub { - private $cacheKey = 'github_repo_data'; - private $cacheTTL = 3600; // 1 hour in seconds - private $client; + private $cacheKey = 'github_repo_data'; + private $cacheTTL = 3600; // 1 hour in seconds + private $client; - public function __construct() - { - $this->client = new Client(); - } + public function __construct() + { + $this->client = new Client(); + } - /** - * Retrieves repository data from GitHub API, using cache if available. - * - * @return array The repository data. - */ - public function getRepoData() - { - // Check if data is cached - if (Cache::exists($this->cacheKey)) { - return Cache::getJson($this->cacheKey); - } + /** + * Retrieves repository data from GitHub API, using cache if available. + * + * @return array the repository data + */ + public function getRepoData() + { + // Check if data is cached + if (Cache::exists($this->cacheKey)) { + return Cache::getJson($this->cacheKey); + } - // Make GET request to GitHub API - $response = $this->client->request('GET', 'https://api.github.com/repos/mythicalltd/mythicaldash', [ - 'headers' => [ - 'Accept' => 'application/vnd.github+json', - 'X-GitHub-Api-Version' => '2022-11-28', - 'User-Agent' => 'MythicalClient', - ], - ]); + // Make GET request to GitHub API + $response = $this->client->request('GET', 'https://api.github.com/repos/mythicalltd/mythicaldash', [ + 'headers' => [ + 'Accept' => 'application/vnd.github+json', + 'X-GitHub-Api-Version' => '2022-11-28', + 'User-Agent' => 'MythicalClient', + ], + ]); - $data = json_decode($response->getBody()->getContents(), true); + $data = json_decode($response->getBody()->getContents(), true); - // Cache the response - Cache::putJson($this->cacheKey, $data, $this->cacheTTL); + // Cache the response + Cache::putJson($this->cacheKey, $data, $this->cacheTTL); - return $data; - } + return $data; + } } diff --git a/backend/app/Hooks/MythicalAPP.php b/backend/app/Hooks/MythicalAPP.php index d99db61..0b15966 100755 --- a/backend/app/Hooks/MythicalAPP.php +++ b/backend/app/Hooks/MythicalAPP.php @@ -240,13 +240,13 @@ public static function sendManualResponse(int $code, ?string $error, ?string $me 'debug_debug' => APP_DEBUG, 'debug_version' => APP_VERSION, 'debug_telemetry' => TELEMETRY, - 'debug' => [ - 'useRedis' => REDIS_ENABLED, - 'rateLimit' => [ - 'enabled' => REDIS_ENABLED, - 'limit' => RATE_LIMIT, - ], - ] + 'debug' => [ + 'useRedis' => REDIS_ENABLED, + 'rateLimit' => [ + 'enabled' => REDIS_ENABLED, + 'limit' => RATE_LIMIT, + ], + ], ], ];