diff --git a/public/static/style.css b/public/static/style.css index 02f1dbc..3806bf2 100644 --- a/public/static/style.css +++ b/public/static/style.css @@ -27,10 +27,6 @@ a:hover, a:focus { text-decoration: underline; } -.monospace { - font-family: monospace; -} - .gray { color: gray; } @@ -252,6 +248,7 @@ details > summary { details > p { margin: 0.75rem 1rem; + font-family: monospace; } /* -- Detail columns -- */ diff --git a/sql/init_tables.sql b/sql/init_tables.sql index ca50ffa..0383dd8 100644 --- a/sql/init_tables.sql +++ b/sql/init_tables.sql @@ -35,12 +35,11 @@ CREATE TABLE `mail_users` CREATE TABLE `mail_aliases` ( - `alias_id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `user_id` int(10) unsigned NOT NULL, - `mail_address` varchar(255) NOT NULL, - `wildcard_priority` smallint(6) NOT NULL DEFAULT 0, - `created_at` datetime NOT NULL DEFAULT NOW(), - `modified_at` datetime NOT NULL DEFAULT NOW(), + `alias_id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `user_id` int(10) unsigned NOT NULL, + `mail_address` varchar(255) NOT NULL, + `created_at` datetime NOT NULL DEFAULT NOW(), + `modified_at` datetime NOT NULL DEFAULT NOW(), PRIMARY KEY (`alias_id`), UNIQUE KEY `mail_address` (`mail_address`), KEY `user_id` (`user_id`), diff --git a/src/Common/FormData.php b/src/Common/FormData.php index e21fbe2..c8e235c 100644 --- a/src/Common/FormData.php +++ b/src/Common/FormData.php @@ -44,42 +44,25 @@ abstract class FormData // Input validation - Application specific validators - private static function validateMailAddress(string $address, bool $required = true, string $fieldName = 'Mail address'): ?string + protected static function validateUsername(string $username, bool $required = true, string $fieldName = 'Username'): ?string { - // Note: This validator allows '%' as wildcard character inside mail addresses. - if (!$required && $address === '') { + if (!$required && $username === '') { return null; } - $address = strtolower( - self::validateString($address, 3, 100, $fieldName) + $username = strtolower( + self::validateString($username, 3, 100, $fieldName) ); - if (!preg_match('/^[a-z0-9%._+-]+@[a-z0-9%.-]+$/', $address) || preg_match('/^\\.|\\.\\.|\\.@|@\\.|\\.$/', $address)) { + if (!preg_match('/^[a-z0-9._+-]+@[a-z0-9.-]+$/', $username) || preg_match('/^\\.|\\.\\.|\\.@|@\\.|\\.$/', $username)) { throw new InputValidationError("$fieldName is not valid (must be a valid mail address)."); } - return $address; - } - - protected static function validateUsername(string $username, bool $required = true): ?string - { - $username = self::validateMailAddress($username, $required, 'Username'); - - if (strpos($username, '%') !== false) { - throw new InputValidationError('Username must not contain the wildcard character "%" (use a wildcard alias instead).'); - } return $username; } - protected static function validateAliasAddress(string $aliasAddress, bool $isWildcard): string + protected static function validateAliasAddress(string $aliasAddress): string { - $aliasAddress = self::validateMailAddress($aliasAddress, true, 'Alias address'); - - // Check if the address contains a wildcard character - if (!$isWildcard && strpos($aliasAddress, '%') !== false) { - throw new InputValidationError('Non-wildcard alias address must not contain "%" character.'); - } - return $aliasAddress; + return self::validateUsername($aliasAddress, true, 'Alias address'); } protected static function validatePassword(string $password, string $passwordRepeat, bool $required = true): ?string diff --git a/src/Frontend/Accounts/AccountAddAliasData.php b/src/Frontend/Accounts/AccountAddAliasData.php index 4a2469e..6e5a3c6 100644 --- a/src/Frontend/Accounts/AccountAddAliasData.php +++ b/src/Frontend/Accounts/AccountAddAliasData.php @@ -4,34 +4,20 @@ declare(strict_types=1); namespace MailAccountAdmin\Frontend\Accounts; use MailAccountAdmin\Common\FormData; -use MailAccountAdmin\Exceptions\InputValidationError; class AccountAddAliasData extends FormData { private string $aliasAddress; - private bool $isWildcard; - private int $wildcardPriority; - private function __construct(string $aliasAddress, bool $isWildcard, int $wildcardPriority) + private function __construct(string $aliasAddress) { - if ($isWildcard && $wildcardPriority === 0) { - throw new InputValidationError('Wildcard alias must have a wildcard priority other than 0.'); - } elseif (!$isWildcard) { - $wildcardPriority = 0; - } - $this->aliasAddress = $aliasAddress; - $this->isWildcard = $isWildcard; - $this->wildcardPriority = $wildcardPriority; } public static function createFromArray(array $raw): self { - $isWildcard = self::validateBoolOption(trim($raw['is_wildcard'] ?? '')); return new self( - self::validateAliasAddress(trim($raw['alias_address'] ?? ''), $isWildcard), - $isWildcard, - self::validateInteger(trim($raw['wildcard_priority'] ?? '')), + self::validateAliasAddress(trim($raw['alias_address'] ?? '')), ); } @@ -39,14 +25,4 @@ class AccountAddAliasData extends FormData { return $this->aliasAddress; } - - public function isWildcard(): bool - { - return $this->isWildcard; - } - - public function getWildcardPriority(): int - { - return $this->wildcardPriority; - } } diff --git a/src/Frontend/Accounts/AccountHandler.php b/src/Frontend/Accounts/AccountHandler.php index b9a0650..4a71fc0 100644 --- a/src/Frontend/Accounts/AccountHandler.php +++ b/src/Frontend/Accounts/AccountHandler.php @@ -278,22 +278,14 @@ class AccountHandler // Check if account exists $this->ensureAccountExists($accountId); - $unescapedAddress = $address = $aliasAddData->getAliasAddress(); - $wildcardPriority = 0; - - if ($aliasAddData->isWildcard()) { - // If it's a wildcard alias, escape underscores - $address = str_replace('_', '\\_', $address); - $wildcardPriority = $aliasAddData->getWildcardPriority(); - } - // Check if alias address is still available + $address = $aliasAddData->getAliasAddress(); if (!$this->accountRepository->checkUsernameAvailable($address) || !$this->aliasRepository->checkAliasAvailable($address)) { - throw new InputValidationError("Alias address \"$unescapedAddress\" is not available."); + throw new InputValidationError("Alias address \"$address\" is not available."); } // Create alias in database - $this->aliasRepository->createNewAlias($accountId, $address, $wildcardPriority); + $this->aliasRepository->createNewAlias($accountId, $address); } diff --git a/src/Models/Alias.php b/src/Models/Alias.php index e636c82..3fe7413 100644 --- a/src/Models/Alias.php +++ b/src/Models/Alias.php @@ -10,23 +10,14 @@ class Alias private int $id; private int $userId; private string $mailAddress; - private int $wildcardPriority; private DateTimeImmutable $createdAt; private DateTimeImmutable $modifiedAt; - private function __construct( - int $id, - int $userId, - string $mailAddress, - int $wildcardPriority, - DateTimeImmutable $createdAt, - DateTimeImmutable $modifiedAt - ) + private function __construct(int $id, int $userId, string $mailAddress, DateTimeImmutable $createdAt, DateTimeImmutable $modifiedAt) { $this->id = $id; $this->userId = $userId; $this->mailAddress = $mailAddress; - $this->wildcardPriority = $wildcardPriority; $this->createdAt = $createdAt; $this->modifiedAt = $modifiedAt; } @@ -37,7 +28,6 @@ class Alias (int)$data['alias_id'], (int)$data['user_id'], $data['mail_address'], - (int)$data['wildcard_priority'], new DateTimeImmutable($data['created_at']), new DateTimeImmutable($data['modified_at']), ); @@ -53,24 +43,11 @@ class Alias return $this->userId; } - public function getMailAddress(bool $unescape = true): string + public function getMailAddress(): string { - if ($this->isWildcard() && $unescape) { - return str_replace('\\_', '_', $this->mailAddress); - } return $this->mailAddress; } - public function isWildcard(): bool - { - return $this->wildcardPriority !== 0; - } - - public function getWildcardPriority(): int - { - return $this->wildcardPriority; - } - public function getCreatedAt(): DateTimeImmutable { return $this->createdAt; diff --git a/src/Repositories/AliasRepository.php b/src/Repositories/AliasRepository.php index 9a4d615..45ed640 100644 --- a/src/Repositories/AliasRepository.php +++ b/src/Repositories/AliasRepository.php @@ -11,11 +11,11 @@ class AliasRepository extends BaseRepository { public function fetchAliasesForUserId(int $userId): array { - $statement = $this->pdo->prepare('SELECT * FROM mail_aliases WHERE user_id = :user_id ORDER BY wildcard_priority, mail_address'); + $statement = $this->pdo->prepare('SELECT * FROM mail_aliases WHERE user_id = :user_id ORDER BY mail_address'); $statement->execute(['user_id' => $userId]); $rows = $statement->fetchAll(PDO::FETCH_ASSOC); - // Create Alias models from rows + // Create Account models from rows $aliasList = []; foreach ($rows as $row) { $aliasList[] = Alias::createFromArray($row); @@ -43,20 +43,12 @@ class AliasRepository extends BaseRepository return $statement->rowCount() === 0; } - public function createNewAlias(int $userId, string $mailAddress, int $wildcardPriority = 0): void + public function createNewAlias(int $userId, string $mailAddress): void { - $query = ' - INSERT INTO mail_aliases - (user_id, mail_address, wildcard_priority) - VALUES - (:user_id, :mail_address, :wildcard_priority) - '; - - $statement = $this->pdo->prepare($query); + $statement = $this->pdo->prepare('INSERT INTO mail_aliases (user_id, mail_address) VALUES (:user_id, :mail_address)'); $statement->execute([ 'user_id' => $userId, 'mail_address' => $mailAddress, - 'wildcard_priority' => $wildcardPriority, ]); } diff --git a/templates/account_create.html.twig b/templates/account_create.html.twig index 15c8bd2..246aae7 100644 --- a/templates/account_create.html.twig +++ b/templates/account_create.html.twig @@ -24,7 +24,7 @@
{{ domainList ? domainList | join(', ') : 'No domains exist yet.' }}
+{{ domainList ? domainList | join(', ') : 'No domains exist yet.' }}
| - | Address | -Wildcard (priority) | +Address | Created at |
|---|---|---|---|---|
| - | - {% if alias.isWildcard() %} - Yes ({{ alias.getWildcardPriority() }}) - {% else %} - No - {% endif %} - | {{ alias.getCreatedAt() | date }} | ||
| - - | -||||
| Wildcard: | -- - - + | |||
- Wildcard aliases use % as a placeholder for any amount of characters (zero or more),
- e.g. %@example.com or example-%@example.com.
-
- Additionally, a wildcard priority must be specified. When a mail address is looked up that - matches multiple (wildcard) aliases, the alias with the lowest wildcard priority will be used. - The priority must not be 0 (internally, the value 0 stands for regular non-wildcard aliases). -
-