diff --git a/config/emails/email-change.txt b/config/emails/email-change.txt new file mode 100644 index 00000000..26eff162 --- /dev/null +++ b/config/emails/email-change.txt @@ -0,0 +1,7 @@ +Flashii.net E-mail Change + +Hey %username%, + +The e-mail address associated with your account has been changed from %email_previous% to %email_new% from IP address %ip_address%. + +If you didn't do this yourself please contact us immediately . diff --git a/config/emails/password-change.txt b/config/emails/password-change.txt new file mode 100644 index 00000000..4cbc6ea9 --- /dev/null +++ b/config/emails/password-change.txt @@ -0,0 +1,7 @@ +Flashii.net Password Change + +Hey %username%, + +Your password has been changed from IP address %ip_address%. + +If you didn't do this yourself please contact us immediately . diff --git a/config/emails/password-recovery.txt b/config/emails/password-recovery.txt new file mode 100644 index 00000000..75345ea0 --- /dev/null +++ b/config/emails/password-recovery.txt @@ -0,0 +1,7 @@ +Flashii.net Password Recovery + +Hey %username%, + +You, or someone pretending to be you, has requested a password reset for your account. + +Your verification code is: %token% diff --git a/misuzu.php b/misuzu.php index f63c1e23..41e54f5a 100644 --- a/misuzu.php +++ b/misuzu.php @@ -44,7 +44,6 @@ require_once 'src/emotes.php'; require_once 'src/general.php'; require_once 'src/git.php'; require_once 'src/integer.php'; -require_once 'src/mail.php'; require_once 'src/manage.php'; require_once 'src/news.php'; require_once 'src/otp.php'; @@ -101,6 +100,15 @@ DB::init(DB::buildDSN($dbConfig), $dbConfig['username'] ?? '', $dbConfig['passwo ]); Config::init(); +Mailer::init(Config::get('mail.method', Config::TYPE_STR), [ + 'host' => Config::get('mail.host', Config::TYPE_STR), + 'port' => Config::get('mail.port', Config::TYPE_INT, 25), + 'username' => Config::get('mail.username', Config::TYPE_STR), + 'password' => Config::get('mail.password', Config::TYPE_STR), + 'encryption' => Config::get('mail.encryption', Config::TYPE_STR), + 'sender_name' => Config::get('mail.sender.name', Config::TYPE_STR), + 'sender_addr' => Config::get('mail.sender.address', Config::TYPE_STR), +]); mail_settings([ 'method' => Config::get('mail.method', Config::TYPE_STR), 'host' => Config::get('mail.host', Config::TYPE_STR), diff --git a/public/auth/password.php b/public/auth/password.php index 14e4b208..a1a92c61 100644 --- a/public/auth/password.php +++ b/public/auth/password.php @@ -102,23 +102,17 @@ while($canResetPassword) { throw new UnexpectedValueException('A verification code failed to insert.'); } - $messageBody = << $forgotUser['username'], + 'token' => $verificationCode, + ]); -You, or someone pretending to be you, has requested a password reset for your account. - -Your verification code is: {$verificationCode} - -If you weren't the person who requested this reset, please send a reply to this e-mail. -MSG; - - $message = mail_compose( + $recoveryMail = Mailer::sendMessage( [$forgotUser['email'] => $forgotUser['username']], - 'Flashii Password Reset', - $messageBody + $recoveryMessage['subject'], $recoveryMessage['message'] ); - if(!mail_send($message)) { + if(!$recoveryMail) { $notices[] = "Failed to send reset email, please contact the administrator."; user_recovery_token_invalidate($forgotUser['user_id'], $verificationCode); break; diff --git a/src/Mailer.php b/src/Mailer.php new file mode 100644 index 00000000..0cdb9e96 --- /dev/null +++ b/src/Mailer.php @@ -0,0 +1,72 @@ +setHost(self::$mailerConfig['host'] ?? ''); + self::$mailer->setPort(self::$mailerConfig['port'] ?? 25); + self::$mailer->setUsername(self::$mailerConfig['username'] ?? ''); + self::$mailer->setPassword(self::$mailerConfig['password'] ?? ''); + self::$mailer->setEncryption(self::$mailerConfig['encryption'] ?? ''); + } + } + + return self::$mailer; + } + + public static function sendMessage(array $to, string $subject, string $contents, bool $bcc = false): bool { + $message = new Swift_Message($subject); + + $message->setFrom([ + $config['sender_addr'] ?? 'sys@flashii.net' => $config['sender_name'] ?? 'Flashii', + ]); + + if($bcc) + $message->setBcc($to); + else + $message->setTo($to); + + $message->setBody($contents); + + return self::getMailer()->send($message); + } + + public static function template(string $name, array $vars = []): array { + $path = sprintf(self::TEMPLATE_PATH, $name); + + if(!is_file($path)) + throw new InvalidArgumentException('Invalid e-mail template name.'); + + $tpl = file_get_contents($path); + + // Normalise newlines + $tpl = str_replace("\n", "\r\n", str_replace("\r\n", "\n", $tpl)); + + foreach($vars as $key => $val) + $tpl = str_replace("%{$key}%", $val, $tpl); + + [$subject, $message] = explode("\r\n\r\n", $tpl, 2); + + return compact('subject', 'message'); + } +} diff --git a/src/mail.php b/src/mail.php deleted file mode 100644 index 3304c93d..00000000 --- a/src/mail.php +++ /dev/null @@ -1,113 +0,0 @@ - MSZ_MAIL_NULL, - 'smtp' => MSZ_MAIL_SMTP, - 'sendmail' => MSZ_MAIL_SENDMAIL, -]); - -define('MSZ_MAIL_DEFAULT_SENDER_NAME', 'Misuzu System'); -define('MSZ_MAIL_DEFAULT_SENDER_ADDRESS', 'sys@msz.lh'); - -function mail_settings($param = null) { - static $settings = []; - - if(!empty($param)) { - if(is_array($param)) { - $settings = array_merge_recursive($settings, $param); - } elseif(is_string($param)) { - return $settings[$param] ?? null; - } - } - - return $settings; -} - -function mail_init_if_prepared(): bool { - return !empty(mail_instance()) || mail_init(mail_settings()); -} - -function mail_instance($newObject = null) { - static $object = null; - - if(!empty($newObject)) { - $object = $newObject; - } - - return $object; -} - -function mail_init(array $options = []): bool { - if(!empty(mail_instance())) { - return true; - } - - mail_settings($options); - $method = $options['method'] ?? ''; - - if(array_key_exists($method, MSZ_MAIL_METHODS)) { - $method = MSZ_MAIL_METHODS[$method]; - } - - if(!in_array($method, MSZ_MAIL_METHODS)) { - return false; - } - - $transport = new $method; - - switch($method) { - case MSZ_MAIL_SENDMAIL: - if(!empty($options['command'])) { - $transport->setCommand($options['command']); - } - break; - - case MSZ_MAIL_SMTP: - $transport->setHost($options['host'] ?? ''); - $transport->setPort(intval($options['port'] ?? 25)); - - if(!empty($options['encryption'])) { - $transport->setEncryption($options['encryption']); - } - - if(!empty($options['username'])) { - $transport->setUsername($options['username']); - } - - if(!empty($options['password'])) { - $transport->setPassword($options['password']); - } - break; - } - - mail_instance($transport); - return true; -} - -function mail_default_sender(): array { - return [ - mail_settings('sender_email') ?? MSZ_MAIL_DEFAULT_SENDER_ADDRESS => - mail_settings('sender_name') ?? MSZ_MAIL_DEFAULT_SENDER_NAME - ]; -} - -function mail_send(Swift_Message $mail): int { - if(!mail_init_if_prepared()) { - return 0; - } - - return mail_instance()->send($mail); -} - -function mail_compose( - array $addressees, - string $subject, - string $body -): Swift_Message { - return (new Swift_Message($subject)) - ->setFrom(mail_default_sender()) - ->setTo($addressees) - ->setBody($body); -}