diff --git a/.vscode/settings.json b/.vscode/settings.json index 1cea3ba8..7c47e8c7 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "Predis", "recommand", "Regen", + "SOURCECODE", "Swal", "sweetalert" ] diff --git a/backend/app/Api/User/Auth/ForgotPassword.php b/backend/app/Api/User/Auth/ForgotPassword.php index 9f8d43f9..0ad4bcfc 100755 --- a/backend/app/Api/User/Auth/ForgotPassword.php +++ b/backend/app/Api/User/Auth/ForgotPassword.php @@ -31,6 +31,7 @@ use MythicalClient\App; use MythicalClient\Chat\User; +use MythicalClient\CloudFlare\CloudFlareRealIP; use MythicalSystems\CloudFlare\Turnstile; use MythicalClient\Config\ConfigInterface; use MythicalSystems\CloudFlare\CloudFlare; @@ -60,7 +61,7 @@ $appInstance->BadRequest('Bad Request', ['error_code' => 'TURNSTILE_FAILED']); } $cfTurnstileResponse = $_POST['turnstileResponse']; - if (!Turnstile::validate($cfTurnstileResponse, CloudFlare::getRealUserIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { + if (!Turnstile::validate($cfTurnstileResponse, CloudFlareRealIP::getRealIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { $appInstance->BadRequest('Invalid TurnStile Key', ['error_code' => 'TURNSTILE_FAILED']); } } diff --git a/backend/app/Api/User/Auth/Login.php b/backend/app/Api/User/Auth/Login.php index e4ce07a0..0e3ca02e 100755 --- a/backend/app/Api/User/Auth/Login.php +++ b/backend/app/Api/User/Auth/Login.php @@ -31,6 +31,7 @@ use MythicalClient\App; use MythicalClient\Chat\User; +use MythicalClient\CloudFlare\CloudFlareRealIP; use MythicalClient\Mail\Mail; use MythicalSystems\CloudFlare\Turnstile; use MythicalClient\Config\ConfigInterface; @@ -66,7 +67,7 @@ $appInstance->BadRequest('Bad Request', ['error_code' => 'TURNSTILE_FAILED']); } $cfTurnstileResponse = $_POST['turnstileResponse']; - if (!Turnstile::validate($cfTurnstileResponse, CloudFlare::getRealUserIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { + if (!Turnstile::validate($cfTurnstileResponse, CloudFlareRealIP::getRealIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { $appInstance->BadRequest('Invalid TurnStile Key', ['error_code' => 'TURNSTILE_FAILED']); } } diff --git a/backend/app/Api/User/Auth/Register.php b/backend/app/Api/User/Auth/Register.php index 07de6add..a5cbaf0f 100755 --- a/backend/app/Api/User/Auth/Register.php +++ b/backend/app/Api/User/Auth/Register.php @@ -31,6 +31,7 @@ use MythicalClient\App; use MythicalClient\Chat\User; +use MythicalClient\CloudFlare\CloudFlareRealIP; use MythicalSystems\CloudFlare\Turnstile; use MythicalClient\Config\ConfigInterface; use MythicalSystems\CloudFlare\CloudFlare; @@ -74,7 +75,7 @@ $appInstance->BadRequest('Bad Request', ['error_code' => 'TURNSTILE_FAILED']); } $cfTurnstileResponse = $_POST['turnstileResponse']; - if (!Turnstile::validate($cfTurnstileResponse, CloudFlare::getRealUserIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { + if (!Turnstile::validate($cfTurnstileResponse, CloudFlareRealIP::getRealIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { $appInstance->BadRequest('Invalid TurnStile Key', ['error_code' => 'TURNSTILE_FAILED']); } } @@ -97,7 +98,7 @@ if (User::exists(UserColumns::EMAIL, $email)) { $appInstance->BadRequest('Bad Request', ['error_code' => 'EMAIL_ALREADY_IN_USE']); } - User::register($username, $password, $email, $firstName, $lastName, CloudFlare::getRealUserIP()); + User::register($username, $password, $email, $firstName, $lastName, CloudFlareRealIP::getRealIP()); App::OK('User registered', []); } catch (Exception $e) { diff --git a/backend/app/Api/User/Auth/ResetPassword.php b/backend/app/Api/User/Auth/ResetPassword.php index 96057abd..a8b14788 100755 --- a/backend/app/Api/User/Auth/ResetPassword.php +++ b/backend/app/Api/User/Auth/ResetPassword.php @@ -32,6 +32,7 @@ use MythicalClient\App; use MythicalClient\Chat\User; use MythicalClient\Chat\Verification; +use MythicalClient\CloudFlare\CloudFlareRealIP; use MythicalSystems\CloudFlare\Turnstile; use MythicalClient\Config\ConfigInterface; use MythicalSystems\CloudFlare\CloudFlare; @@ -94,7 +95,7 @@ $appInstance->BadRequest('Bad Request', ['error_code' => 'TURNSTILE_FAILED']); } $cfTurnstileResponse = $_POST['turnstileResponse']; - if (!Turnstile::validate($cfTurnstileResponse, CloudFlare::getRealUserIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { + if (!Turnstile::validate($cfTurnstileResponse, CloudFlareRealIP::getRealIP(), $config->getSetting(ConfigInterface::TURNSTILE_KEY_PRIV, 'XXXX'))) { $appInstance->BadRequest('Invalid TurnStile Key', ['error_code' => 'TURNSTILE_FAILED']); } } diff --git a/backend/app/Api/User/Auth/Verify.php b/backend/app/Api/User/Auth/Verify.php new file mode 100755 index 00000000..df54fad8 --- /dev/null +++ b/backend/app/Api/User/Auth/Verify.php @@ -0,0 +1,68 @@ + - All rights reserved + * (c) NaysKutzu - All rights reserved + * (c) Cassian Gherman - All rights reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use MythicalClient\App; +use MythicalClient\Chat\User; +use MythicalClient\Chat\Verification; +use MythicalClient\Chat\columns\UserColumns; +use MythicalClient\Chat\columns\EmailVerificationColumns; + +$router->get('/api/user/auth/verify', function (): void { + App::init(); + $appInstance = App::getInstance(true); + $config = $appInstance->getConfig(); + + $appInstance->allowOnlyGET(); + + if (isset($_GET['code']) && $_GET['code'] != '') { + $code = $_GET['code']; + + if (Verification::verify($code, EmailVerificationColumns::$type_verify)) { + if (User::exists(UserColumns::UUID, Verification::getUserUUID($code))) { + $token = User::getInfo(User::getTokenFromUUID(Verification::getUserUUID($code)), UserColumns::ACCOUNT_TOKEN, false); + if ($token != null && $token != '') { + setcookie('user_token', $token, time() + 3600, '/'); + User::updateInfo(User::getTokenFromUUID(Verification::getUserUUID($code)), UserColumns::VERIFIED, 'true', false); + Verification::delete($code); + die(header('location: /')); + } else { + $appInstance->BadRequest('Bad Request', ['error_code' => 'INVALID_USER','email_code' => $code]); + } + } else { + $appInstance->BadRequest('Bad Request', ['error_code' => 'INVALID_USER','email_code' => $code]); + } + } else { + $appInstance->BadRequest('Bad Request', ['error_code' => 'INVALID_CODE', 'email_code' => $code]); + } + } else { + $appInstance->BadRequest('Bad Request', ['error_code' => 'MISSING_CODE']); + } +}); diff --git a/backend/app/Api/User/Session.php b/backend/app/Api/User/Session.php index bd47fbd0..7caf1840 100755 --- a/backend/app/Api/User/Session.php +++ b/backend/app/Api/User/Session.php @@ -36,7 +36,7 @@ use MythicalClient\Chat\Session; use MythicalClient\Chat\columns\UserColumns; -$router->post('/api/user/session', function (): void { +$router->post('/api/user/session/info/update', function (): void { App::init(); $appInstance = App::getInstance(true); $config = $appInstance->getConfig(); @@ -44,6 +44,34 @@ $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']); + } + + $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()]); + } }); $router->post('/api/user/session/billing/update', function (): void { @@ -113,7 +141,11 @@ $config = $appInstance->getConfig(); $appInstance->allowOnlyGET(); + $session = new Session($appInstance); + if (isset($_GET['ip']) && $_GET['ip'] != '') { + $session->setInfo(UserColumns::LAST_IP, $_GET['ip'], false); + } $accountToken = $session->SESSION_KEY; try { $billing = Billing::getBillingData(User::getInfo($accountToken, UserColumns::UUID, false)); @@ -136,7 +168,7 @@ 'deleted' => User::getInfo($accountToken, UserColumns::DELETED, false), 'last_seen' => User::getInfo($accountToken, UserColumns::LAST_SEEN, false), 'first_seen' => User::getInfo($accountToken, UserColumns::FIRST_SEEN, false), - 'background' => User::getInfo($accountToken, UserColumns::BACKGROUND, true), + 'background' => User::getInfo($accountToken, UserColumns::BACKGROUND, false), 'role_name' => Roles::getUserRoleName(User::getInfo($accountToken, UserColumns::UUID, false)), 'role_real_name' => Roles::getUserRoleName(User::getInfo($accountToken, UserColumns::UUID, false)), ], diff --git a/backend/app/App.php b/backend/app/App.php index e6ea303f..553b4539 100755 --- a/backend/app/App.php +++ b/backend/app/App.php @@ -103,9 +103,7 @@ public function __construct(bool $softBoot) } catch (\Exception $e) { self::init(); self::InternalServerError($e->getMessage(), null); - } - } /** @@ -258,4 +256,12 @@ public function decrypt(string $data): string { return XChaCha20::decrypt($data, $_ENV['DATABASE_ENCRYPTION_KEY'], true); } + + public function generateCode() : string { + $code = base64_encode(random_bytes(64)); + $code = str_replace('=', '', $code); + $code = str_replace('+','', $code); + $code = str_replace('/','', $code); + return $code; + } } diff --git a/backend/app/Chat/Session.php b/backend/app/Chat/Session.php index e7f242f6..345fb0da 100755 --- a/backend/app/Chat/Session.php +++ b/backend/app/Chat/Session.php @@ -33,6 +33,8 @@ use MythicalClient\App; use MythicalClient\Chat\columns\UserColumns; +use MythicalClient\CloudFlare\CloudFlareRealIP; +use MythicalSystems\CloudFlare\CloudFlare; class Session extends Database { @@ -44,6 +46,9 @@ public function __construct(App $app) if (isset($_COOKIE['user_token']) && !$_COOKIE['user_token'] == '') { if (User::exists(UserColumns::ACCOUNT_TOKEN, $_COOKIE['user_token'])) { try { + header("Access-Control-Allow-Origin: *"); + header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); + header("Access-Control-Allow-Headers: Content-Type, Authorization"); $this->app = $app; $this->SESSION_KEY = $_COOKIE['user_token']; $this->updateLastSeen(); @@ -84,7 +89,10 @@ public function updateLastSeen(): void { try { $con = self::getPdoConnection(); + $ip = CloudFlareRealIP::getRealIP(); + $this->app->getLogger()->info('Updating last seen for ' . $this->SESSION_KEY . ' with IP: ' . $ip); $con->exec('UPDATE ' . User::TABLE_NAME . ' SET last_seen = NOW() WHERE token = "' . $this->SESSION_KEY . '";'); + $con->exec('UPDATE ' . User::TABLE_NAME . ' SET last_ip = "'.$ip.'" WHERE token = "' . $this->SESSION_KEY . '";'); } catch (\Exception $e) { $this->app->getLogger()->error('Failed to update last seen: ' . $e->getMessage()); } diff --git a/backend/app/Chat/User.php b/backend/app/Chat/User.php index 8c776d32..e03cf127 100755 --- a/backend/app/Chat/User.php +++ b/backend/app/Chat/User.php @@ -121,7 +121,7 @@ public static function register(string $username, string $password, string $emai */ if (Mail::isEnabled()) { try { - $verify_token = base64_encode(random_bytes(16)); + $verify_token = App::getInstance(true)->generateCode(); Verification::add($verify_token, $uuid, EmailVerificationColumns::$type_verify); Verify::sendMail($uuid, $verify_token); } catch (\Exception $e) { @@ -170,7 +170,7 @@ public static function forgotPassword(string $email): bool if ($user) { if (Mail::isEnabled()) { try { - $verify_token = base64_encode(random_bytes(16)); + $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) { diff --git a/backend/app/CloudFlare/CloudFlareRealIP.php b/backend/app/CloudFlare/CloudFlareRealIP.php new file mode 100755 index 00000000..7b5a3013 --- /dev/null +++ b/backend/app/CloudFlare/CloudFlareRealIP.php @@ -0,0 +1,15 @@ +getLogger()->error('(' . APP_SOURCECODE_DIR . '/Mail/Mail.php) [send] Failed to send email: ' . $e->getMessage()); + } } /** diff --git a/backend/app/Mail/services/SMTPServer.php b/backend/app/Mail/services/SMTPServer.php index ac834fca..09bcf875 100755 --- a/backend/app/Mail/services/SMTPServer.php +++ b/backend/app/Mail/services/SMTPServer.php @@ -40,42 +40,46 @@ class SMTPServer { public static function send(string $to, string $subject, string $body) { - $config = new ConfigFactory(Database::getPdoConnection()); + try { + $config = new ConfigFactory(Database::getPdoConnection()); - if ($config->getSetting(ConfigInterface::SMTP_ENABLED, 'false') == 'true') { - if ( - $config->getSetting(ConfigInterface::SMTP_HOST, null) == null - || $config->getSetting(ConfigInterface::SMTP_PORT, null) == null - || $config->getSetting(ConfigInterface::SMTP_USER, null) == null - || $config->getSetting(ConfigInterface::SMTP_PASS, null) == null - || $config->getSetting(ConfigInterface::SMTP_FROM, null) == null - ) { - App::getInstance(true)->getLogger()->info('Failed to send email, SMTP settings are not configured.'); + if ($config->getSetting(ConfigInterface::SMTP_ENABLED, 'false') == 'true') { + if ( + $config->getSetting(ConfigInterface::SMTP_HOST, null) == null + || $config->getSetting(ConfigInterface::SMTP_PORT, null) == null + || $config->getSetting(ConfigInterface::SMTP_USER, null) == null + || $config->getSetting(ConfigInterface::SMTP_PASS, null) == null + || $config->getSetting(ConfigInterface::SMTP_FROM, null) == null + ) { + App::getInstance(true)->getLogger()->info('Failed to send email, SMTP settings are not configured.'); - return; - } - $mail = new \PHPMailer\PHPMailer\PHPMailer(false); - try { - $mail->isSMTP(); - $mail->Host = $config->getSetting(ConfigInterface::SMTP_HOST, null); - $mail->SMTPAuth = true; - $mail->Username = $config->getSetting(ConfigInterface::SMTP_USER, null); - $mail->Password = $config->getSetting(ConfigInterface::SMTP_PASS, null); - $mail->SMTPSecure = $config->getSetting(ConfigInterface::SMTP_ENCRYPTION, 'ssl'); - $mail->Port = $config->getSetting(ConfigInterface::SMTP_PORT, null); - $mail->setFrom($config->getSetting(ConfigInterface::SMTP_FROM, null), $config->getSetting(ConfigInterface::APP_NAME, null)); - $mail->addReplyTo($config->getSetting(ConfigInterface::SMTP_FROM, null), $config->getSetting(ConfigInterface::APP_NAME, null)); - $mail->isHTML(true); - $mail->Subject = $subject; - $mail->Body = $body; - $mail->addAddress($to); - $mail->send(); - } catch (\Exception $e) { - App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); + return; + } + $mail = new \PHPMailer\PHPMailer\PHPMailer(false); + try { + $mail->isSMTP(); + $mail->Host = $config->getSetting(ConfigInterface::SMTP_HOST, null); + $mail->SMTPAuth = true; + $mail->Username = $config->getSetting(ConfigInterface::SMTP_USER, null); + $mail->Password = $config->getSetting(ConfigInterface::SMTP_PASS, null); + $mail->SMTPSecure = $config->getSetting(ConfigInterface::SMTP_ENCRYPTION, 'ssl'); + $mail->Port = $config->getSetting(ConfigInterface::SMTP_PORT, null); + $mail->setFrom($config->getSetting(ConfigInterface::SMTP_FROM, null), $config->getSetting(ConfigInterface::APP_NAME, null)); + $mail->addReplyTo($config->getSetting(ConfigInterface::SMTP_FROM, null), $config->getSetting(ConfigInterface::APP_NAME, null)); + $mail->isHTML(true); + $mail->Subject = $subject; + $mail->Body = $body; + $mail->addAddress($to); + $mail->send(); + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); - return; - } + return; + } + } + } catch (\Exception $e) { + App::getInstance(true)->getLogger()->error('Failed to send email: ' . $e->getMessage()); } // No exception handling!! diff --git a/backend/storage/migrations/20.11.2024-21.41-create-mail-template.sql b/backend/storage/migrations/20.11.2024-21.41-create-mail-template.sql index baa5420f..740afe86 100755 --- a/backend/storage/migrations/20.11.2024-21.41-create-mail-template.sql +++ b/backend/storage/migrations/20.11.2024-21.41-create-mail-template.sql @@ -8,14 +8,13 @@ CREATE TABLE `active` ENUM ('false', 'true') NOT NULL DEFAULT 'false', `date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) - ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; + ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci; -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('verify', 'Verify your ${app_name} account

${app_name}

Verify your email address

Hi ${first_name} ${last_name},

Thanks for signing up for ${app_name}. Please verify your email address by clicking the button below.

Verify Email Address

If you did not create an account with ${app_name}, you can safely ignore this email.

', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('reset_password', 'Reset your ${app_name} password

${app_name}

Reset your password

Hi ${first_name} ${last_name},

We received a request to reset your password for your ${app_name} account. Click the button below to reset it.

Reset Password

If you did not request a password reset, you can safely ignore this email.

', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('new_login', 'New login to your ${app_name} account

${app_name}

New login detected

Hi ${first_name} ${last_name},

We detected a new login to your ${app_name} account from a new device. If this was you, you can safely ignore this email. If this was not you, please secure your account immediately.

Secure Account
', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('new_invoice', 'New Invoice from ${app_name}

${app_name}

New Invoice

Hi ${first_name} ${last_name},

You have a new invoice from ${app_name}. Please find the details below:

Invoice Number: ${invoice_number}

Amount: ${invoice_amount}

View Invoice

If you have any questions, please contact our support team.

', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('product_ready', 'Your ${app_name} product is ready

${app_name}

Your product is ready

Hi ${first_name} ${last_name},

Your ${app_name} product is ready. You can access it using the following details:

Location: ${product_location}

Username: ${username}

Password: ${password}

Additional Info: ${additional_info}

Access Product
', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('product_suspended', 'Your ${app_name} product was suspended

${app_name}

Product Suspended

Hi ${first_name} ${last_name},

Your ${app_name} product was suspended. Please contact support for more information.

', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('invoice_paid', 'Invoice Paid - ${app_name}

${app_name}

Invoice Paid

Hi ${first_name} ${last_name},

Thank you for your payment. Your invoice ${invoice_number} has been paid successfully.

Amount: ${invoice_amount}

View Invoice
', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('account_deactivation', 'Account Deactivation - ${app_name}

${app_name}

Account Deactivation

Hi ${first_name} ${last_name},

We are sorry to see you go. Your ${app_name} account has been deactivated. If you change your mind, you can reactivate your account within 30 days.

Reactivate Account
', 'true'); -INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('welcome', 'Welcome to ${app_name}

${app_name}

Welcome to ${app_name}

Hi ${first_name} ${last_name},

Welcome to ${app_name}! We are excited to have you on board. Get started by exploring our features and services.

Go to Dashboard
', 'true'); \ No newline at end of file +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('verify', 'Verify your ${app_name} account

${app_name}

Verify your email address

Dear Sir or Madam,

Hi ${first_name} ${last_name},

Thanks for signing up for ${app_name}. Please verify your email address by clicking the button below.

Verify Email Address

If you did not create an account with ${app_name}, you can safely ignore this email.

', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('reset_password', 'Reset your ${app_name} password

${app_name}

Reset your password

Dear Sir or Madam,

Hi ${first_name} ${last_name},

We received a request to reset your password for your ${app_name} account. Click the button below to reset it.

Reset Password

If you did not request a password reset, you can safely ignore this email.

', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('new_login', 'New login to your ${app_name} account

${app_name}

New login detected

Dear Sir or Madam,

Hi ${first_name} ${last_name},

We detected a new login to your ${app_name} account from a new device. If this was you, you can safely ignore this email. If this was not you, please secure your account immediately.

Secure Account
', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('new_invoice', 'New Invoice from ${app_name}

${app_name}

New Invoice

Dear Sir or Madam,

Hi ${first_name} ${last_name},

You have a new invoice from ${app_name}. Please find the details below:

Invoice Number: ${invoice_number}

Amount: ${invoice_amount}

View Invoice

If you have any questions, please contact our support team.

', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('product_ready', 'Your ${app_name} product is ready

${app_name}

Your product is ready

Dear Sir or Madam,

Hi ${first_name} ${last_name},

Your ${app_name} product is ready. You can access it using the following details:

Location: ${product_location}

Username: ${username}

Password: ${password}

Additional Info: ${additional_info}

Access Product
', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('product_suspended', 'Your ${app_name} product was suspended

${app_name}

Product Suspended

Dear Sir or Madam,

Hi ${first_name} ${last_name},

Your ${app_name} product was suspended. Please contact support for more information.

', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('invoice_paid', 'Invoice Paid - ${app_name}

${app_name}

Invoice Paid

Dear Sir or Madam,

Hi ${first_name} ${last_name},

Thank you for your payment. Your invoice ${invoice_number} has been paid successfully.

Amount: ${invoice_amount}

View Invoice
', 'true'); +INSERT INTO `mythicalclient_mail_templates` (`name`, `content`, `active`) VALUES ('welcome', 'Welcome to ${app_name}

${app_name}

Welcome to ${app_name}

Dear Sir or Madam,

Hi ${first_name} ${last_name},

Welcome to ${app_name}! We are excited to have you on board. Get started by exploring our features and services.

Go to Dashboard
', 'true'); \ No newline at end of file diff --git a/frontend/src/mythicalclient/Session.ts b/frontend/src/mythicalclient/Session.ts index f67b907a..5ae21cbc 100755 --- a/frontend/src/mythicalclient/Session.ts +++ b/frontend/src/mythicalclient/Session.ts @@ -65,6 +65,7 @@ class Session { // Update session info every 1 minute setInterval(updateSessionInfo, 60000); } + } export default Session; diff --git a/frontend/src/views/auth/ResetPassword.vue b/frontend/src/views/auth/ResetPassword.vue index a52492d9..f7ffd004 100755 --- a/frontend/src/views/auth/ResetPassword.vue +++ b/frontend/src/views/auth/ResetPassword.vue @@ -30,8 +30,8 @@ document.title = t('auth.pages.reset_password.page.title'); const checkResetCode = async (code: string) => { try { const response = await Auth.isLoginVerifyTokenValid(code); - if (!response.ok) { - window.location.href = '/auth/login'; + if (!response.success) { + location.href = '/auth/login?invalid_code'; } } catch (error) { console.error('Error checking reset code:', error); @@ -40,12 +40,12 @@ const checkResetCode = async (code: string) => { const init = async () => { const urlParams = new URLSearchParams(window.location.search); - const resetCode = urlParams.get('code'); + const resetCode = urlParams.get('token'); if (resetCode) { await checkResetCode(resetCode); } else { - window.location.href = '/auth/login'; + alert("Missing reset code"); } }; @@ -54,10 +54,10 @@ init(); // This function is called when the form is submitted const handleSubmit = async () => { const urlParams = new URLSearchParams(window.location.search); - const resetCode = urlParams.get('code'); + const resetCode = urlParams.get('token'); loading.value = true; - const response = await Auth.resetPassword(resetCode || "", form.password, form.confirmPassword, form.turnstileResponse); + const response = await Auth.resetPassword(form.confirmPassword, form.password,resetCode || "", form.turnstileResponse); try { if (!response.success) { diff --git a/nginx.conf b/nginx.conf index d991fdfc..059ce885 100755 --- a/nginx.conf +++ b/nginx.conf @@ -143,4 +143,4 @@ server { location ~ /\.ht { deny all; } -} \ No newline at end of file +}