Added new alias formats and option to change alias separator

This commit is contained in:
Will Browning
2026-02-11 11:22:04 +00:00
parent 4653e1b58c
commit daf6408e31
26 changed files with 17557 additions and 8507 deletions

View File

@@ -74,3 +74,12 @@ ANONADDY_USE_PROXY_AUTHENTICATION=false
ANONADDY_PROXY_AUTHENTICATION_USER_ID_HEADER=X-User
ANONADDY_PROXY_AUTHENTICATION_NAME_HEADER=X-Name
ANONADDY_PROXY_AUTHENTICATION_EMAIL_HEADER=X-Email
# Optional: override word/name lists with a comma-separated list or path to a PHP file that returns an array
# ANONADDY_BLACKLIST=reserved,admin,root
# ANONADDY_MALE_FIRST_NAMES=config/lists/custom_male_first.php
# ANONADDY_FEMALE_FIRST_NAMES=
# ANONADDY_SURNAMES=
# ANONADDY_WORDLIST=
# ANONADDY_ADJECTIVES=
# ANONADDY_NOUNS=

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\UpdateAliasSeparatorRequest;
class AliasSeparatorController extends Controller
{
public function update(UpdateAliasSeparatorRequest $request)
{
user()->alias_separator = $request->separator;
user()->save();
return back()->with(['flash' => 'Alias Separator Updated Successfully']);
}
}

View File

@@ -131,6 +131,12 @@ class AliasController extends Controller
if ($format === 'random_words') {
// Random Words
$localPart = user()->generateRandomWordLocalPart();
} elseif ($format === 'random_male_name') {
$localPart = user()->generateRandomNameLocalPart('male');
} elseif ($format === 'random_female_name') {
$localPart = user()->generateRandomNameLocalPart('female');
} elseif ($format === 'random_noun') {
$localPart = user()->generateRandomNounLocalPart();
} elseif ($format === 'uuid') {
// UUID
$localPart = Uuid::uuid4();

View File

@@ -20,6 +20,7 @@ class SettingController extends Controller
return Inertia::render('Settings/General', [
'defaultAliasDomain' => user()->default_alias_domain,
'defaultAliasFormat' => user()->default_alias_format,
'aliasSeparator' => user()->alias_separator,
'loginRedirect' => user()->login_redirect->value,
'displayFromFormat' => user()->display_from_format->value,
'useReplyTo' => user()->use_reply_to,

View File

@@ -45,7 +45,7 @@ class StoreAliasRequest extends FormRequest
Rule::in($this->user()->domainOptions()),
],
'description' => 'nullable|max:200',
'format' => 'nullable|in:random_characters,uuid,random_words,custom',
'format' => 'nullable|in:random_characters,uuid,random_words,random_male_name,random_female_name,random_noun,custom',
'recipient_ids' => [
'bail',
'nullable',

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateAliasSeparatorRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'separator' => ['required', 'string', 'in:.,_,-,random'],
];
}
}

View File

@@ -27,7 +27,7 @@ class UpdateDefaultAliasFormatRequest extends FormRequest
'format' => [
'required',
'string',
'in:random_characters,uuid,random_words,custom',
'in:random_characters,uuid,random_words,random_male_name,random_female_name,random_noun,custom',
],
];
}

View File

@@ -37,6 +37,7 @@ class UserResource extends JsonResource
'default_recipient_id' => $this->default_recipient_id,
'default_alias_domain' => $this->default_alias_domain,
'default_alias_format' => $this->default_alias_format,
'alias_separator' => $this->alias_separator,
'recipient_count' => $this->recipients()->count(),
'active_domain_count' => $this->domains()->where('active', true)->count(),
'active_shared_domain_alias_count' => $this->activeSharedDomainAliases()->count(),

View File

@@ -51,6 +51,7 @@ class User extends Authenticatable implements MustVerifyEmail
'defer_new_aliases_until',
'default_alias_domain',
'default_alias_format',
'alias_separator',
'use_reply_to',
'store_failed_deliveries',
'save_alias_last_used',
@@ -585,11 +586,49 @@ class User extends Authenticatable implements MustVerifyEmail
}
}
/**
* Get the separator character to use when generating alias local parts.
* Resolves 'random' to one of '.', '_', '-' per generation.
*/
public function aliasSeparatorForGeneration(): string
{
$setting = $this->alias_separator ?? '.';
if ($setting === 'random') {
return ['.', '_', '-'][mt_rand(0, 2)];
}
return $setting;
}
public function generateRandomWordLocalPart()
{
return collect(config('anonaddy.wordlist'))
->random(2)
->implode('.').mt_rand(0, 999);
$sep = $this->aliasSeparatorForGeneration();
$words = collect(config('anonaddy.wordlist'))->random(2)->map(fn ($w) => strtolower($w));
return $words->implode($sep).mt_rand(0, 999);
}
public function generateRandomNameLocalPart(string $gender): string
{
$firstNames = $gender === 'male'
? config('anonaddy.male_first_names')
: config('anonaddy.female_first_names');
$first = collect($firstNames)->random();
$surname = collect(config('anonaddy.surnames'))->random();
$digits = str_pad((string) mt_rand(0, 999), 3, '0', STR_PAD_LEFT);
$sep = $this->aliasSeparatorForGeneration();
return strtolower($first).$sep.strtolower($surname).$digits;
}
public function generateRandomNounLocalPart(): string
{
$adjective = collect(config('anonaddy.adjectives'))->random();
$noun = collect(config('anonaddy.nouns'))->random();
$digits = str_pad((string) mt_rand(0, 999), 3, '0', STR_PAD_LEFT);
$sep = $this->aliasSeparatorForGeneration();
return strtolower($adjective).$sep.strtolower($noun).$digits;
}
public function generateRandomCharacterLocalPart(int $length): string

169
composer.lock generated
View File

@@ -165,16 +165,16 @@
},
{
"name": "brick/math",
"version": "0.14.5",
"version": "0.14.8",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40"
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/618a8077b3c326045e10d5788ed713b341fcfe40",
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40",
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629",
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629",
"shasum": ""
},
"require": {
@@ -213,7 +213,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.5"
"source": "https://github.com/brick/math/tree/0.14.8"
},
"funding": [
{
@@ -221,7 +221,7 @@
"type": "github"
}
],
"time": "2026-02-03T18:06:51+00:00"
"time": "2026-02-10T14:33:43+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -734,29 +734,29 @@
},
{
"name": "doctrine/deprecations",
"version": "1.1.5",
"version": "1.1.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
"reference": "d4fe3e6fd9bb9e72557a19674f44d8ac7db4c6ca",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0"
},
"conflict": {
"phpunit/phpunit": "<=7.5 || >=13"
"phpunit/phpunit": "<=7.5 || >=14"
},
"require-dev": {
"doctrine/coding-standard": "^9 || ^12 || ^13",
"phpstan/phpstan": "1.4.10 || 2.1.11",
"doctrine/coding-standard": "^9 || ^12 || ^14",
"phpstan/phpstan": "1.4.10 || 2.1.30",
"phpstan/phpstan-phpunit": "^1.0 || ^2",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12.4 || ^13.0",
"psr/log": "^1 || ^2 || ^3"
},
"suggest": {
@@ -776,9 +776,9 @@
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/1.1.5"
"source": "https://github.com/doctrine/deprecations/tree/1.1.6"
},
"time": "2025-04-07T20:06:18+00:00"
"time": "2026-02-07T07:09:04+00:00"
},
{
"name": "doctrine/inflector",
@@ -1899,16 +1899,16 @@
},
{
"name": "laravel/framework",
"version": "v12.49.0",
"version": "v12.51.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5"
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/4bde4530545111d8bdd1de6f545fa8824039fcb5",
"reference": "4bde4530545111d8bdd1de6f545fa8824039fcb5",
"url": "https://api.github.com/repos/laravel/framework/zipball/ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
"reference": "ce4de3feb211e47c4f959d309ccf8a2733b1bc16",
"shasum": ""
},
"require": {
@@ -2117,34 +2117,34 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2026-01-28T03:40:49+00:00"
"time": "2026-02-10T18:20:19+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.3.11",
"version": "v0.3.13",
"source": {
"type": "git",
"url": "https://github.com/laravel/prompts.git",
"reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217"
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/prompts/zipball/dd2a2ed95acacbcccd32fd98dee4c946ae7a7217",
"reference": "dd2a2ed95acacbcccd32fd98dee4c946ae7a7217",
"url": "https://api.github.com/repos/laravel/prompts/zipball/ed8c466571b37e977532fb2fd3c272c784d7050d",
"reference": "ed8c466571b37e977532fb2fd3c272c784d7050d",
"shasum": ""
},
"require": {
"composer-runtime-api": "^2.2",
"ext-mbstring": "*",
"php": "^8.1",
"symfony/console": "^6.2|^7.0"
"symfony/console": "^6.2|^7.0|^8.0"
},
"conflict": {
"illuminate/console": ">=10.17.0 <10.25.0",
"laravel/framework": ">=10.17.0 <10.25.0"
},
"require-dev": {
"illuminate/collections": "^10.0|^11.0|^12.0",
"illuminate/collections": "^10.0|^11.0|^12.0|^13.0",
"mockery/mockery": "^1.5",
"pestphp/pest": "^2.3|^3.4|^4.0",
"phpstan/phpstan": "^1.12.28",
@@ -2174,36 +2174,36 @@
"description": "Add beautiful and user-friendly forms to your command-line applications.",
"support": {
"issues": "https://github.com/laravel/prompts/issues",
"source": "https://github.com/laravel/prompts/tree/v0.3.11"
"source": "https://github.com/laravel/prompts/tree/v0.3.13"
},
"time": "2026-01-27T02:55:06+00:00"
"time": "2026-02-06T12:17:10+00:00"
},
{
"name": "laravel/sanctum",
"version": "v4.3.0",
"version": "v4.3.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/sanctum.git",
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a"
"reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/c978c82b2b8ab685468a7ca35224497d541b775a",
"reference": "c978c82b2b8ab685468a7ca35224497d541b775a",
"url": "https://api.github.com/repos/laravel/sanctum/zipball/e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76",
"reference": "e3b85d6e36ad00e5db2d1dcc27c81ffdf15cbf76",
"shasum": ""
},
"require": {
"ext-json": "*",
"illuminate/console": "^11.0|^12.0",
"illuminate/contracts": "^11.0|^12.0",
"illuminate/database": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"illuminate/console": "^11.0|^12.0|^13.0",
"illuminate/contracts": "^11.0|^12.0|^13.0",
"illuminate/database": "^11.0|^12.0|^13.0",
"illuminate/support": "^11.0|^12.0|^13.0",
"php": "^8.2",
"symfony/console": "^7.0"
"symfony/console": "^7.0|^8.0"
},
"require-dev": {
"mockery/mockery": "^1.6",
"orchestra/testbench": "^9.15|^10.8",
"orchestra/testbench": "^9.15|^10.8|^11.0",
"phpstan/phpstan": "^1.10"
},
"type": "library",
@@ -2239,31 +2239,31 @@
"issues": "https://github.com/laravel/sanctum/issues",
"source": "https://github.com/laravel/sanctum"
},
"time": "2026-01-22T22:27:01+00:00"
"time": "2026-02-07T17:19:31+00:00"
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.8",
"version": "v2.0.9",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b"
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b",
"reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e",
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0|^13.0",
"nesbot/carbon": "^2.67|^3.0",
"pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
"symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0"
},
"type": "library",
"extra": {
@@ -2300,20 +2300,20 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2026-01-08T16:22:46+00:00"
"time": "2026-02-03T06:55:34+00:00"
},
{
"name": "laravel/tinker",
"version": "v2.11.0",
"version": "v2.11.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/tinker.git",
"reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468"
"reference": "c9f80cc835649b5c1842898fb043f8cc098dd741"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/tinker/zipball/3d34b97c9a1747a81a3fde90482c092bd8b66468",
"reference": "3d34b97c9a1747a81a3fde90482c092bd8b66468",
"url": "https://api.github.com/repos/laravel/tinker/zipball/c9f80cc835649b5c1842898fb043f8cc098dd741",
"reference": "c9f80cc835649b5c1842898fb043f8cc098dd741",
"shasum": ""
},
"require": {
@@ -2364,9 +2364,9 @@
],
"support": {
"issues": "https://github.com/laravel/tinker/issues",
"source": "https://github.com/laravel/tinker/tree/v2.11.0"
"source": "https://github.com/laravel/tinker/tree/v2.11.1"
},
"time": "2025-12-19T19:16:45+00:00"
"time": "2026-02-06T14:12:35+00:00"
},
{
"name": "laravel/ui",
@@ -3539,16 +3539,16 @@
},
{
"name": "nette/schema",
"version": "v1.3.3",
"version": "v1.3.4",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004"
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/2befc2f42d7c715fd9d95efc31b1081e5d765004",
"reference": "2befc2f42d7c715fd9d95efc31b1081e5d765004",
"url": "https://api.github.com/repos/nette/schema/zipball/086497a2f34b82fede9b5a41cc8e131d087cd8f7",
"reference": "086497a2f34b82fede9b5a41cc8e131d087cd8f7",
"shasum": ""
},
"require": {
@@ -3556,8 +3556,8 @@
"php": "8.1 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^2.0@stable",
"nette/tester": "^2.6",
"phpstan/phpstan": "^2.0@stable",
"tracy/tracy": "^2.8"
},
"type": "library",
@@ -3598,9 +3598,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.3"
"source": "https://github.com/nette/schema/tree/v1.3.4"
},
"time": "2025-10-30T22:57:59+00:00"
"time": "2026-02-08T02:54:00+00:00"
},
{
"name": "nette/utils",
@@ -9097,16 +9097,16 @@
},
{
"name": "laravel/pint",
"version": "v1.27.0",
"version": "v1.27.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90"
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/pint/zipball/c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
"reference": "c67b4195b75491e4dfc6b00b1c78b68d86f54c90",
"url": "https://api.github.com/repos/laravel/pint/zipball/54cca2de13790570c7b6f0f94f37896bee4abcb5",
"reference": "54cca2de13790570c7b6f0f94f37896bee4abcb5",
"shasum": ""
},
"require": {
@@ -9117,13 +9117,13 @@
"php": "^8.2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.92.4",
"illuminate/view": "^12.44.0",
"larastan/larastan": "^3.8.1",
"laravel-zero/framework": "^12.0.4",
"friendsofphp/php-cs-fixer": "^3.93.1",
"illuminate/view": "^12.51.0",
"larastan/larastan": "^3.9.2",
"laravel-zero/framework": "^12.0.5",
"mockery/mockery": "^1.6.12",
"nunomaduro/termwind": "^2.3.3",
"pestphp/pest": "^3.8.4"
"pestphp/pest": "^3.8.5"
},
"bin": [
"builds/pint"
@@ -9160,7 +9160,7 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
"time": "2026-01-05T16:49:17+00:00"
"time": "2026-02-10T20:00:20+00:00"
},
{
"name": "mockery/mockery",
@@ -9999,16 +9999,16 @@
},
{
"name": "phpunit/phpunit",
"version": "11.5.50",
"version": "11.5.53",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3"
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fdfc727f0fcacfeb8fcb30c7e5da173125b58be3",
"reference": "fdfc727f0fcacfeb8fcb30c7e5da173125b58be3",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a997a653a82845f1240d73ee73a8a4e97e4b0607",
"reference": "a997a653a82845f1240d73ee73a8a4e97e4b0607",
"shasum": ""
},
"require": {
@@ -10023,7 +10023,7 @@
"phar-io/version": "^3.2.1",
"php": ">=8.2",
"phpunit/php-code-coverage": "^11.0.12",
"phpunit/php-file-iterator": "^5.1.0",
"phpunit/php-file-iterator": "^5.1.1",
"phpunit/php-invoker": "^5.0.1",
"phpunit/php-text-template": "^4.0.1",
"phpunit/php-timer": "^7.0.1",
@@ -10035,6 +10035,7 @@
"sebastian/exporter": "^6.3.2",
"sebastian/global-state": "^7.0.2",
"sebastian/object-enumerator": "^6.0.1",
"sebastian/recursion-context": "^6.0.3",
"sebastian/type": "^5.1.3",
"sebastian/version": "^5.0.2",
"staabm/side-effects-detector": "^1.0.5"
@@ -10080,7 +10081,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.50"
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.53"
},
"funding": [
{
@@ -10104,7 +10105,7 @@
"type": "tidelift"
}
],
"time": "2026-01-27T05:59:18+00:00"
"time": "2026-02-10T12:28:25+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -11616,16 +11617,16 @@
},
{
"name": "spatie/ray",
"version": "1.45.0",
"version": "1.46.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/ray.git",
"reference": "68920c418d10fe103722d366faa575533d26434f"
"reference": "a227afd1899581d81af1fd5ebec03d34157ed2d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/ray/zipball/68920c418d10fe103722d366faa575533d26434f",
"reference": "68920c418d10fe103722d366faa575533d26434f",
"url": "https://api.github.com/repos/spatie/ray/zipball/a227afd1899581d81af1fd5ebec03d34157ed2d2",
"reference": "a227afd1899581d81af1fd5ebec03d34157ed2d2",
"shasum": ""
},
"require": {
@@ -11685,7 +11686,7 @@
],
"support": {
"issues": "https://github.com/spatie/ray/issues",
"source": "https://github.com/spatie/ray/tree/1.45.0"
"source": "https://github.com/spatie/ray/tree/1.46.0"
},
"funding": [
{
@@ -11697,7 +11698,7 @@
"type": "other"
}
],
"time": "2026-01-26T18:45:30+00:00"
"time": "2026-02-06T07:38:10+00:00"
},
{
"name": "staabm/side-effects-detector",

File diff suppressed because it is too large Load Diff

3739
config/lists/adjectives.php Normal file

File diff suppressed because it is too large Load Diff

543
config/lists/blacklist.php Normal file
View File

@@ -0,0 +1,543 @@
<?php
return [
'.htaccess',
'.htpasswd',
'.well-known',
'400',
'401',
'403',
'404',
'405',
'406',
'407',
'408',
'409',
'410',
'411',
'412',
'413',
'414',
'415',
'416',
'417',
'421',
'422',
'423',
'424',
'426',
'428',
'429',
'431',
'500',
'501',
'502',
'503',
'504',
'505',
'506',
'507',
'508',
'509',
'510',
'511',
'about',
'about-us',
'abuse',
'access',
'account',
'accounts',
'activate',
'active',
'ad',
'add',
'addy',
'admin',
'administration',
'administrator',
'ads',
'advertise',
'advertising',
'aes128-ctr',
'aes128-gcm',
'aes192-ctr',
'aes256-ctr',
'aes256-gcm',
'affiliate',
'affiliates',
'ajax',
'alert',
'alerts',
'alias',
'alpha',
'amp',
'analytics',
'anonaddy',
'api',
'app',
'apps',
'asc',
'assets',
'atom',
'auth',
'authentication',
'authorize',
'autoconfig',
'autodiscover',
'avatar',
'backup',
'banner',
'banners',
'beta',
'billing',
'billings',
'blog',
'blogs',
'board',
'bookmark',
'bookmarks',
'bounce',
'bounces',
'broadcasthost',
'business',
'buy',
'cache',
'calendar',
'campaign',
'captcha',
'careers',
'cart',
'cas',
'categories',
'category',
'cdn',
'cgi',
'cgi-bin',
'chacha20-poly1305',
'change',
'channel',
'channels',
'chart',
'chat',
'checkout',
'clear',
'client',
'close',
'cms',
'com',
'comment',
'comments',
'community',
'compare',
'compose',
'config',
'connect',
'contact',
'contest',
'cookies',
'copy',
'copyright',
'count',
'create',
'crossdomain.xml',
'css',
'curve25519-sha256',
'customer',
'customers',
'customize',
'dashboard',
'db',
'deactivate',
'deals',
'debug',
'delete',
'desc',
'destroy',
'dev',
'developer',
'developers',
'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group14-sha1',
'disconnect',
'discuss',
'dns',
'dns0',
'dns1',
'dns2',
'dns3',
'dns4',
'docs',
'documentation',
'domain',
'download',
'downloads',
'downvote',
'draft',
'drop',
'ecdh-sha2-nistp256',
'ecdh-sha2-nistp384',
'ecdh-sha2-nistp521',
'edit',
'editor',
'email',
'enterprise',
'error',
'errors',
'event',
'events',
'example',
'exception',
'exit',
'explore',
'export',
'extensions',
'false',
'family',
'faq',
'faqs',
'favicon.ico',
'features',
'feed',
'feedback',
'feeds',
'file',
'files',
'filter',
'follow',
'follower',
'followers',
'following',
'fonts',
'forgot',
'forgot-password',
'forgotpassword',
'form',
'forms',
'forum',
'forums',
'forward',
'forwarder',
'friend',
'friends',
'ftp',
'get',
'git',
'go',
'group',
'groups',
'guest',
'guidelines',
'guides',
'head',
'header',
'help',
'hide',
'hmac-sha',
'hmac-sha1',
'hmac-sha1-etm',
'hmac-sha2-256',
'hmac-sha2-256-etm',
'hmac-sha2-512',
'hmac-sha2-512-etm',
'home',
'host',
'hosting',
'hostmaster',
'htpasswd',
'http',
'httpd',
'https',
'humans.txt',
'icons',
'images',
'imap',
'img',
'import',
'index',
'info',
'insert',
'investors',
'invitations',
'invite',
'invites',
'invoice',
'is',
'isatap',
'issues',
'it',
'jobs',
'join',
'js',
'json',
'keybase.txt',
'learn',
'legal',
'license',
'licensing',
'like',
'limit',
'live',
'load',
'local',
'localdomain',
'localhost',
'lock',
'login',
'logout',
'lost-password',
'mail',
'mail0',
'mail1',
'mail2',
'mail3',
'mail4',
'mail5',
'mail6',
'mail7',
'mail8',
'mail9',
'mailer',
'mailer-daemon',
'mailerdaemon',
'map',
'marketing',
'marketplace',
'master',
'me',
'media',
'member',
'members',
'message',
'messages',
'metrics',
'mis',
'mobile',
'moderator',
'modify',
'more',
'mx',
'my',
'net',
'network',
'new',
'news',
'newsletter',
'newsletters',
'next',
'nil',
'no-reply',
'nobody',
'noc',
'none',
'noreply',
'notification',
'notifications',
'ns',
'ns0',
'ns1',
'ns2',
'ns3',
'ns4',
'ns5',
'ns6',
'ns7',
'ns8',
'ns9',
'null',
'oauth',
'oauth2',
'offer',
'offers',
'online',
'openid',
'openpgpkey',
'order',
'orders',
'overview',
'owner',
'page',
'pages',
'partners',
'passwd',
'password',
'pay',
'payment',
'payments',
'photo',
'photos',
'pixel',
'plans',
'plugins',
'policies',
'policy',
'pop',
'pop3',
'popular',
'portfolio',
'post',
'postfix',
'postmaster',
'poweruser',
'preferences',
'premium',
'press',
'previous',
'pricing',
'print',
'privacy',
'privacy-policy',
'private',
'prod',
'product',
'production',
'profile',
'profiles',
'project',
'projects',
'public',
'purchase',
'put',
'quota',
'recipient',
'redirect',
'reduce',
'refund',
'refunds',
'register',
'registration',
'remove',
'replies',
'reply',
'report',
'request',
'request-password',
'reset',
'reset-password',
'response',
'return',
'returns',
'review',
'reviews',
'robots.txt',
'root',
'rootuser',
'rsa-sha2-2',
'rsa-sha2-512',
'rss',
'rules',
'sales',
'save',
'script',
'sdk',
'search',
'secure',
'security',
'select',
'services',
'session',
'sessions',
'settings',
'setup',
'share',
'shift',
'shop',
'signin',
'signup',
'site',
'sitemap',
'sites',
'smtp',
'sort',
'source',
'sql',
'ssh',
'ssh-rsa',
'ssl',
'ssladmin',
'ssladministrator',
'sslwebmaster',
'stage',
'staging',
'stat',
'static',
'statistics',
'stats',
'status',
'store',
'style',
'styles',
'stylesheet',
'stylesheets',
'subdomain',
'subscribe',
'sudo',
'super',
'superuser',
'support',
'survey',
'sync',
'sysadmin',
'system',
'tablet',
'tag',
'tags',
'team',
'telnet',
'terms',
'terms-of-use',
'test',
'testimonials',
'theme',
'themes',
'today',
'tools',
'topic',
'topics',
'tour',
'training',
'translate',
'translations',
'trending',
'trial',
'true',
'umac-128',
'umac-128-etm',
'umac-64',
'umac-64-etm',
'undefined',
'unfollow',
'unlike',
'unsub',
'unsubscribe',
'update',
'upgrade',
'usenet',
'user',
'username',
'users',
'uucp',
'var',
'verify',
'video',
'view',
'void',
'vote',
'webmail',
'webmaster',
'website',
'widget',
'widgets',
'wiki',
'wpad',
'write',
'www',
'www-data',
'www1',
'www2',
'www3',
'www4',
'you',
'yourname',
'yourusername',
'zlib',
];

View File

@@ -0,0 +1,428 @@
<?php
return [
'abbie',
'abby',
'abigail',
'ada',
'adalyn',
'adalynn',
'addison',
'adele',
'adeline',
'agatha',
'agnes',
'aileen',
'aimee',
'alana',
'alayah',
'alba',
'alex',
'alexa',
'alexandra',
'alexandria',
'alexis',
'alice',
'alicia',
'alina',
'alison',
'alivia',
'aliyah',
'allegra',
'allison',
'ally',
'alma',
'alyssa',
'amber',
'amelia',
'amy',
'anabel',
'anastasia',
'andrea',
'angel',
'angela',
'angelica',
'anna',
'annabel',
'annabella',
'annabelle',
'anne',
'annie',
'arabella',
'aspen',
'athena',
'audrey',
'aurora',
'autumn',
'ava',
'averie',
'avery',
'bailey',
'barbara',
'beatrice',
'bella',
'belle',
'bernadette',
'beryl',
'beth',
'bethany',
'betsy',
'betty',
'blair',
'blake',
'bonnie',
'brianna',
'bridget',
'brielle',
'brinley',
'britney',
'brooke',
'cadence',
'caitlin',
'caitlyn',
'callie',
'cameron',
'camila',
'camille',
'cara',
'carina',
'carla',
'carly',
'carmen',
'caroline',
'carolyn',
'casey',
'cassandra',
'cassidy',
'catalina',
'catherine',
'cecelia',
'celeste',
'celia',
'charlene',
'charley',
'charlotte',
'chelsea',
'chloe',
'christina',
'christine',
'cindy',
'claire',
'clara',
'claudia',
'cleo',
'connie',
'cora',
'coral',
'courtney',
'crystal',
'dahlia',
'daisy',
'dakota',
'dallas',
'dana',
'danielle',
'daphne',
'darlene',
'deanna',
'debbie',
'deborah',
'delaney',
'delilah',
'della',
'demi',
'diana',
'dolly',
'dora',
'doris',
'dorothy',
'eden',
'edith',
'eileen',
'elaina',
'elaine',
'eleanor',
'elena',
'eliza',
'elizabeth',
'ella',
'ellen',
'ellie',
'eloise',
'elsa',
'elsie',
'emersyn',
'emily',
'emma',
'emmalyn',
'erin',
'esme',
'estella',
'esther',
'eugenia',
'eva',
'evelyn',
'everly',
'faith',
'fallon',
'farrah',
'faye',
'felicity',
'fiona',
'florence',
'frances',
'francesca',
'frankie',
'freya',
'gabriella',
'gemma',
'genesis',
'genevieve',
'georgia',
'georgina',
'gillian',
'gloria',
'goldie',
'grace',
'gracie',
'greta',
'gwen',
'gwendolen',
'hadley',
'hailey',
'hannah',
'harlow',
'harmony',
'harper',
'harriet',
'haven',
'hazel',
'heather',
'heidi',
'helen',
'helena',
'holland',
'holly',
'hope',
'imogen',
'india',
'ingrid',
'irene',
'iris',
'isabel',
'isabella',
'isla',
'ivy',
'jacqueline',
'jade',
'jane',
'janet',
'janice',
'jasmine',
'jean',
'jenna',
'jennifer',
'jenny',
'jessica',
'jessie',
'jillian',
'joan',
'joanna',
'jocelyn',
'jodie',
'jolene',
'jordan',
'jordyn',
'josephine',
'josie',
'joy',
'joyce',
'judith',
'judy',
'julia',
'juliana',
'julie',
'juliet',
'juliette',
'june',
'juno',
'karla',
'kate',
'katherine',
'kathleen',
'katie',
'kayla',
'keira',
'kelly',
'kendall',
'kendra',
'kennedy',
'kensley',
'kimberly',
'kinley',
'kinsley',
'kitty',
'kyla',
'kylee',
'lacey',
'lana',
'lark',
'laura',
'lauren',
'lea',
'leah',
'leanne',
'leighton',
'leila',
'lena',
'lennon',
'leona',
'lesley',
'lexie',
'liberty',
'lilian',
'lilliana',
'lilly',
'lily',
'linda',
'lisa',
'livia',
'lola',
'londyn',
'lottie',
'louisa',
'louise',
'lucille',
'lucy',
'luna',
'lydia',
'lyla',
'mabel',
'macy',
'maddie',
'maddison',
'madeline',
'madison',
'mae',
'maeve',
'maggie',
'makayla',
'margaret',
'margot',
'maria',
'mariah',
'marie',
'marjorie',
'marlene',
'martha',
'mary',
'matilda',
'maureen',
'maya',
'mckenna',
'mckenzie',
'megan',
'melanie',
'melissa',
'melody',
'mercy',
'meredith',
'mia',
'michaela',
'mildred',
'millie',
'minnie',
'miranda',
'molly',
'monica',
'morgan',
'muriel',
'nancy',
'naomi',
'natalie',
'nell',
'nellie',
'nicola',
'nicole',
'nina',
'nora',
'norah',
'olivia',
'opal',
'paige',
'pamela',
'patricia',
'paula',
'pearl',
'peggy',
'penelope',
'penny',
'phoebe',
'piper',
'pippa',
'polly',
'poppy',
'prudence',
'rachel',
'rebecca',
'rena',
'rhea',
'rita',
'robin',
'rosa',
'rose',
'rosemary',
'rosie',
'rowan',
'ruby',
'ruth',
'sadie',
'sally',
'samantha',
'sandra',
'sara',
'sarah',
'sasha',
'savannah',
'scarlett',
'shannon',
'sharon',
'sienna',
'sierra',
'silvia',
'sky',
'sofia',
'sophia',
'sophie',
'stacey',
'stella',
'stephanie',
'susan',
'suzanne',
'sylvia',
'tabitha',
'tallulah',
'tamsin',
'tara',
'taylor',
'tess',
'thea',
'theresa',
'tiffany',
'tilly',
'tina',
'valerie',
'vanessa',
'vera',
'victoria',
'violet',
'virginia',
'vivian',
'wendy',
'willow',
'winifred',
'winnie',
'zara',
'zelda',
'zoe',
];

451
config/lists/male_first.php Normal file
View File

@@ -0,0 +1,451 @@
<?php
return [
'aaron',
'adam',
'addison',
'adrian',
'albert',
'alden',
'alec',
'alex',
'alexander',
'alfie',
'alfred',
'alton',
'alvin',
'andrew',
'andy',
'archie',
'arlo',
'arthur',
'asher',
'austin',
'barney',
'barrett',
'barry',
'beckett',
'ben',
'benjamin',
'benson',
'bentley',
'bertie',
'bill',
'billy',
'blaine',
'blake',
'bobby',
'braden',
'bradley',
'brady',
'brandon',
'brennan',
'brent',
'brett',
'brian',
'brock',
'brody',
'brooks',
'bruce',
'bryce',
'bryson',
'caleb',
'callum',
'calvin',
'camden',
'cameron',
'carl',
'carson',
'carter',
'casey',
'cecil',
'cedric',
'chance',
'chandler',
'charles',
'charlie',
'chester',
'christian',
'christopher',
'clayton',
'clifford',
'clyde',
'cody',
'cole',
'colin',
'collin',
'colton',
'connor',
'conor',
'cooper',
'corbin',
'cory',
'craig',
'crew',
'cullen',
'curtis',
'dale',
'damien',
'damon',
'dane',
'daniel',
'danny',
'darren',
'daryl',
'dave',
'davey',
'david',
'davis',
'dax',
'deacon',
'dean',
'declan',
'dennis',
'derek',
'desmond',
'devon',
'dillon',
'dominic',
'don',
'donald',
'donovan',
'dorian',
'douglas',
'drake',
'drew',
'duke',
'duncan',
'dwayne',
'dylan',
'easton',
'eddie',
'edgar',
'edmund',
'edward',
'eli',
'elijah',
'elliot',
'elliott',
'elton',
'emerson',
'enzo',
'eric',
'ethan',
'evan',
'everett',
'ezekiel',
'ezra',
'felix',
'finlay',
'finley',
'finn',
'fletcher',
'ford',
'forrest',
'foster',
'francis',
'frank',
'frankie',
'franklin',
'fred',
'freddie',
'freddy',
'frederick',
'gareth',
'garrison',
'gary',
'gavin',
'gene',
'george',
'gerald',
'gerard',
'gideon',
'glen',
'glenn',
'gordon',
'graham',
'grant',
'grayson',
'gregory',
'greyson',
'griffin',
'grover',
'gus',
'guy',
'hank',
'harley',
'harold',
'harris',
'harrison',
'harry',
'harvey',
'hayden',
'hayes',
'heath',
'hector',
'henry',
'herbert',
'holden',
'howard',
'hudson',
'hugh',
'hugo',
'hunter',
'ian',
'ira',
'ivan',
'jace',
'jack',
'jackson',
'jacob',
'jaden',
'jagger',
'jake',
'james',
'jameson',
'jamie',
'jared',
'jason',
'jasper',
'jax',
'jay',
'jed',
'jeffrey',
'jeremy',
'jerry',
'jesse',
'jett',
'jimmy',
'joel',
'joey',
'john',
'johnny',
'jon',
'jonathan',
'jordan',
'joseph',
'josh',
'joshua',
'judd',
'jude',
'julian',
'kade',
'kai',
'kaleb',
'kane',
'keith',
'kellan',
'kendrick',
'kenneth',
'kenny',
'kent',
'kevin',
'kieran',
'knox',
'kody',
'kyle',
'lachlan',
'lance',
'landon',
'lane',
'larry',
'lawrence',
'lee',
'leland',
'lennon',
'lennox',
'lenny',
'leo',
'leon',
'leonard',
'lester',
'levi',
'lewis',
'liam',
'lincoln',
'linden',
'lloyd',
'logan',
'louis',
'luca',
'lucas',
'luke',
'lyle',
'mac',
'mack',
'maddox',
'magnus',
'marcus',
'mark',
'marlon',
'marshall',
'martin',
'mason',
'matthew',
'maverick',
'max',
'maximus',
'maxwell',
'melvin',
'merrick',
'micah',
'michael',
'mickey',
'miles',
'miller',
'milo',
'mitchell',
'monroe',
'montgomery',
'morgan',
'murray',
'nash',
'nate',
'nathan',
'nathaniel',
'neil',
'nelson',
'niall',
'nick',
'nickolas',
'nico',
'noah',
'noel',
'nolan',
'norman',
'oliver',
'ollie',
'orlando',
'oscar',
'otis',
'otto',
'owen',
'palmer',
'parker',
'patrick',
'paul',
'percy',
'peyton',
'philip',
'presley',
'preston',
'quentin',
'quinn',
'rafael',
'ralph',
'raphael',
'ray',
'reece',
'reese',
'reggie',
'reginald',
'reid',
'remy',
'rex',
'rhett',
'rhys',
'ricky',
'ridge',
'riley',
'river',
'robbie',
'robert',
'robin',
'rocco',
'rodney',
'roger',
'roland',
'roman',
'ron',
'ronald',
'ronan',
'ronnie',
'rory',
'ross',
'rowan',
'roy',
'royce',
'rudy',
'rupert',
'russell',
'ryan',
'rylan',
'sam',
'samson',
'samuel',
'saul',
'sawyer',
'scott',
'scout',
'sean',
'sebastian',
'seth',
'shane',
'shaun',
'shawn',
'sidney',
'silas',
'simon',
'skyler',
'spencer',
'stanley',
'sterling',
'steve',
'steven',
'stuart',
'sullivan',
'sutton',
'tanner',
'tate',
'tatum',
'ted',
'teddy',
'terrence',
'thaddeus',
'theo',
'theodore',
'thomas',
'tim',
'timothy',
'titus',
'tobias',
'toby',
'tom',
'tommy',
'tony',
'trace',
'travis',
'trent',
'trevor',
'tristan',
'troy',
'tucker',
'turner',
'tyler',
'vance',
'vincent',
'wade',
'walker',
'walter',
'ward',
'warren',
'watson',
'wayne',
'wes',
'wesley',
'weston',
'wilbur',
'wiley',
'wilfred',
'will',
'william',
'winston',
'woods',
'wyatt',
'xander',
'zach',
'zachariah',
'zachary',
'zane',
'zion',
];

2334
config/lists/nouns.php Normal file

File diff suppressed because it is too large Load Diff

1739
config/lists/surnames.php Normal file

File diff suppressed because it is too large Load Diff

7776
config/lists/wordlist.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('alias_separator', 10)->after('default_alias_format')->default('.');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('alias_separator');
});
}
};

158
package-lock.json generated
View File

@@ -792,9 +792,9 @@
}
},
"node_modules/@types/node": {
"version": "25.2.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz",
"integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==",
"version": "25.2.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
@@ -815,39 +815,39 @@
}
},
"node_modules/@vue/compiler-core": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.27.tgz",
"integrity": "sha512-gnSBQjZA+//qDZen+6a2EdHqJ68Z7uybrMf3SPjEGgG4dicklwDVmMC1AeIHxtLVPT7sn6sH1KOO+tS6gwOUeQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.28.tgz",
"integrity": "sha512-kviccYxTgoE8n6OCw96BNdYlBg2GOWfBuOW4Vqwrt7mSKWKwFVvI8egdTltqRgITGPsTFYtKYfxIG8ptX2PJHQ==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.27",
"entities": "^7.0.0",
"@babel/parser": "^7.29.0",
"@vue/shared": "3.5.28",
"entities": "^7.0.1",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.27.tgz",
"integrity": "sha512-oAFea8dZgCtVVVTEC7fv3T5CbZW9BxpFzGGxC79xakTr6ooeEqmRuvQydIiDAkglZEAd09LgVf1RoDnL54fu5w==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.28.tgz",
"integrity": "sha512-/1ZepxAb159jKR1btkefDP+J2xuWL5V3WtleRmxaT+K2Aqiek/Ab/+Ebrw2pPj0sdHO8ViAyyJWfhXXOP/+LQA==",
"license": "MIT",
"dependencies": {
"@vue/compiler-core": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-core": "3.5.28",
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.27.tgz",
"integrity": "sha512-sHZu9QyDPeDmN/MRoshhggVOWE5WlGFStKFwu8G52swATgSny27hJRWteKDSUUzUH+wp+bmeNbhJnEAel/auUQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.28.tgz",
"integrity": "sha512-6TnKMiNkd6u6VeVDhZn/07KhEZuBSn43Wd2No5zaP5s3xm8IqFTHBj84HJah4UepSUJTro5SoqqlOY22FKY96g==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.27",
"@vue/compiler-dom": "3.5.27",
"@vue/compiler-ssr": "3.5.27",
"@vue/shared": "3.5.27",
"@babel/parser": "^7.29.0",
"@vue/compiler-core": "3.5.28",
"@vue/compiler-dom": "3.5.28",
"@vue/compiler-ssr": "3.5.28",
"@vue/shared": "3.5.28",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
"postcss": "^8.5.6",
@@ -855,63 +855,63 @@
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.27.tgz",
"integrity": "sha512-Sj7h+JHt512fV1cTxKlYhg7qxBvack+BGncSpH+8vnN+KN95iPIcqB5rsbblX40XorP+ilO7VIKlkuu3Xq2vjw==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.28.tgz",
"integrity": "sha512-JCq//9w1qmC6UGLWJX7RXzrGpKkroubey/ZFqTpvEIDJEKGgntuDMqkuWiZvzTzTA5h2qZvFBFHY7fAAa9475g==",
"license": "MIT",
"dependencies": {
"@vue/compiler-dom": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-dom": "3.5.28",
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/reactivity": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.27.tgz",
"integrity": "sha512-vvorxn2KXfJ0nBEnj4GYshSgsyMNFnIQah/wczXlsNXt+ijhugmW+PpJ2cNPe4V6jpnBcs0MhCODKllWG+nvoQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz",
"integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==",
"license": "MIT",
"dependencies": {
"@vue/shared": "3.5.27"
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.27.tgz",
"integrity": "sha512-fxVuX/fzgzeMPn/CLQecWeDIFNt3gQVhxM0rW02Tvp/YmZfXQgcTXlakq7IMutuZ/+Ogbn+K0oct9J3JZfyk3A==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz",
"integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/reactivity": "3.5.28",
"@vue/shared": "3.5.28"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.27.tgz",
"integrity": "sha512-/QnLslQgYqSJ5aUmb5F0z0caZPGHRB8LEAQ1s81vHFM5CBfnun63rxhvE/scVb/j3TbBuoZwkJyiLCkBluMpeg==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz",
"integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==",
"license": "MIT",
"dependencies": {
"@vue/reactivity": "3.5.27",
"@vue/runtime-core": "3.5.27",
"@vue/shared": "3.5.27",
"@vue/reactivity": "3.5.28",
"@vue/runtime-core": "3.5.28",
"@vue/shared": "3.5.28",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.27.tgz",
"integrity": "sha512-qOz/5thjeP1vAFc4+BY3Nr6wxyLhpeQgAE/8dDtKo6a6xdk+L4W46HDZgNmLOBUDEkFXV3G7pRiUqxjX0/2zWA==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.28.tgz",
"integrity": "sha512-pf+5ECKGj8fX95bNincbzJ6yp6nyzuLDhYZCeFxUNp8EBrQpPpQaLX3nNCp49+UbgbPun3CeVE+5CXVV1Xydfg==",
"license": "MIT",
"dependencies": {
"@vue/compiler-ssr": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-ssr": "3.5.28",
"@vue/shared": "3.5.28"
},
"peerDependencies": {
"vue": "3.5.27"
"vue": "3.5.28"
}
},
"node_modules/@vue/shared": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.27.tgz",
"integrity": "sha512-dXr/3CgqXsJkZ0n9F3I4elY8wM9jMJpP3pvRG52r6m0tu/MsAFIe6JpXVGeNMd/D9F4hQynWT8Rfuj0bdm9kFQ==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz",
"integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==",
"license": "MIT"
},
"node_modules/@vueform/multiselect": {
@@ -1163,9 +1163,9 @@
}
},
"node_modules/ansi-escapes": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz",
"integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
"integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1272,13 +1272,13 @@
}
},
"node_modules/axios": {
"version": "1.13.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.4.tgz",
"integrity": "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==",
"version": "1.13.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz",
"integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
@@ -1403,9 +1403,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001767",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001767.tgz",
"integrity": "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==",
"version": "1.0.30001769",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz",
"integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==",
"funding": [
{
"type": "opencollective",
@@ -2479,9 +2479,9 @@
}
},
"node_modules/laravel-precognition": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-1.0.1.tgz",
"integrity": "sha512-BYaDUjEclKbxuQTG9yZnRjjD7ag1Xh+8hGOXmcrw91/vpbIOJ8cSFADTI0kvwetIr3AM1vOJzYwaoA9+KHhLwA==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/laravel-precognition/-/laravel-precognition-1.0.2.tgz",
"integrity": "sha512-0H08JDdMWONrL/N314fvsO3FATJwGGlFKGkMF3nNmizVFJaWs17816iM+sX7Rp8d5hUjYCx6WLfsehSKfaTxjg==",
"license": "MIT",
"dependencies": {
"axios": "^1.4.0",
@@ -3475,9 +3475,9 @@
}
},
"node_modules/semver": {
"version": "7.7.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -4163,17 +4163,17 @@
}
},
"node_modules/vue": {
"version": "3.5.27",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.27.tgz",
"integrity": "sha512-aJ/UtoEyFySPBGarREmN4z6qNKpbEguYHMmXSiOGk69czc+zhs0NF6tEFrY8TZKAl8N/LYAkd4JHVd5E/AsSmw==",
"version": "3.5.28",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.28.tgz",
"integrity": "sha512-BRdrNfeoccSoIZeIhyPBfvWSLFP4q8J3u8Ju8Ug5vu3LdD+yTM13Sg4sKtljxozbnuMu1NB1X5HBHRYUzFocKg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.27",
"@vue/compiler-sfc": "3.5.27",
"@vue/runtime-dom": "3.5.27",
"@vue/server-renderer": "3.5.27",
"@vue/shared": "3.5.27"
"@vue/compiler-dom": "3.5.28",
"@vue/compiler-sfc": "3.5.28",
"@vue/runtime-dom": "3.5.28",
"@vue/server-renderer": "3.5.28",
"@vue/shared": "3.5.28"
},
"peerDependencies": {
"typescript": "*"
@@ -4305,9 +4305,9 @@
}
},
"node_modules/webpack": {
"version": "5.105.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
"version": "5.105.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.1.tgz",
"integrity": "sha512-Gdj3X74CLJJ8zy4URmK42W7wTZUJrqL+z8nyGEr4dTN0kb3nVs+ZvjbTOqRYPD7qX4tUmwyHL9Q9K6T1seW6Yw==",
"license": "MIT",
"peer": true,
"dependencies": {

View File

@@ -287,7 +287,7 @@ function getIdFromVerp($verpLocalPart, $verpEmail)
return;
}
$expectedSignature = substr(hash_hmac('sha3-224', $id, $_ENV['ANONADDY_VERP_SECRET'] ?? ''), 0, 8);
$expectedSignature = substr(hash_hmac('sha3-224', $id, $_ENV['ANONADDY_SECRET'] ?? ''), 0, 8);
if ($signature !== $expectedSignature) {
logData('VERP invalid signature: '.$verpEmail);

26
postfix/composer.lock generated
View File

@@ -8,16 +8,16 @@
"packages": [
{
"name": "brick/math",
"version": "0.14.5",
"version": "0.14.8",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40"
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/math/zipball/618a8077b3c326045e10d5788ed713b341fcfe40",
"reference": "618a8077b3c326045e10d5788ed713b341fcfe40",
"url": "https://api.github.com/repos/brick/math/zipball/63422359a44b7f06cae63c3b429b59e8efcc0629",
"reference": "63422359a44b7f06cae63c3b429b59e8efcc0629",
"shasum": ""
},
"require": {
@@ -56,7 +56,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
"source": "https://github.com/brick/math/tree/0.14.5"
"source": "https://github.com/brick/math/tree/0.14.8"
},
"funding": [
{
@@ -64,7 +64,7 @@
"type": "github"
}
],
"time": "2026-02-03T18:06:51+00:00"
"time": "2026-02-10T14:33:43+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -682,27 +682,27 @@
},
{
"name": "laravel/serializable-closure",
"version": "v2.0.8",
"version": "v2.0.9",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b"
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/7581a4407012f5f53365e11bafc520fd7f36bc9b",
"reference": "7581a4407012f5f53365e11bafc520fd7f36bc9b",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/8f631589ab07b7b52fead814965f5a800459cb3e",
"reference": "8f631589ab07b7b52fead814965f5a800459cb3e",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"illuminate/support": "^10.0|^11.0|^12.0",
"illuminate/support": "^10.0|^11.0|^12.0|^13.0",
"nesbot/carbon": "^2.67|^3.0",
"pestphp/pest": "^2.36|^3.0|^4.0",
"phpstan/phpstan": "^2.0",
"symfony/var-dumper": "^6.2.0|^7.0.0"
"symfony/var-dumper": "^6.2.0|^7.0.0|^8.0.0"
},
"type": "library",
"extra": {
@@ -739,7 +739,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2026-01-08T16:22:46+00:00"
"time": "2026-02-03T06:55:34+00:00"
},
{
"name": "nesbot/carbon",

View File

@@ -1657,6 +1657,18 @@ const aliasFormatOptions = [
value: 'random_words',
label: 'Random Words',
},
{
value: 'random_male_name',
label: 'Random Male Name',
},
{
value: 'random_female_name',
label: 'Random Female Name',
},
{
value: 'random_noun',
label: 'Random Noun',
},
{
value: 'custom',
label: 'Custom',

View File

@@ -326,7 +326,7 @@
<div>
<label
for="default-alias-format"
class="block text-sm font-medium leading-6 text-grey-600"
class="block text-sm font-medium leading-6 text-grey-600 dark:text-white"
>Select Default Format</label
>
<div class="block relative w-full mt-2">
@@ -369,6 +369,27 @@
>
Random Words
</option>
<option
value="random_male_name"
:selected="defaultAliasFormat === 'random_male_name' ? 'selected' : ''"
class="dark:bg-grey-900"
>
Random Male Name
</option>
<option
value="random_female_name"
:selected="defaultAliasFormat === 'random_female_name' ? 'selected' : ''"
class="dark:bg-grey-900"
>
Random Female Name
</option>
<option
value="random_noun"
:selected="defaultAliasFormat === 'random_noun' ? 'selected' : ''"
class="dark:bg-grey-900"
>
Random Noun
</option>
<option
value="custom"
:selected="defaultAliasFormat === 'custom' ? 'selected' : ''"
@@ -406,6 +427,92 @@
</div>
</div>
<div class="py-10">
<div class="space-y-1">
<h3 class="text-lg font-medium leading-6 text-grey-900 dark:text-white">
Alias Separator
</h3>
<p class="text-base text-grey-700 dark:text-grey-200">
The character used between words in aliases with the following formats: Random Words,
Random Male/Female Name, Random Noun and Custom Shared Domain. For example, with period:
<code class="rounded bg-grey-100 dark:bg-grey-800 px-1"
>word.word123@{{ defaultAliasDomain }}</code
>; with underscore:
<code class="rounded bg-grey-100 dark:bg-grey-800 px-1"
>word_word123@{{ defaultAliasDomain }}</code
>; with hyphen:
<code class="rounded bg-grey-100 dark:bg-grey-800 px-1"
>word-word123@{{ defaultAliasDomain }}</code
>.
</p>
</div>
<div class="mt-4">
<form
@submit.prevent="
aliasSeparatorForm.post(route('settings.alias_separator'), {
preserveScroll: true,
})
"
>
<div class="grid grid-cols-1 mb-6">
<div>
<label
for="alias-separator"
class="block text-sm font-medium leading-6 text-grey-600 dark:text-white"
>Select Separator</label
>
<div class="block relative w-full mt-2">
<select
id="alias-separator"
v-model="aliasSeparatorForm.separator"
name="separator"
required
class="relative block w-full rounded border-0 bg-transparent py-2 text-grey-900 dark:text-white dark:bg-white/5 ring-1 ring-inset focus:z-10 focus:ring-2 focus:ring-inset sm:text-base sm:leading-6"
:class="
aliasSeparatorForm.errors.separator
? 'ring-red-300 focus:ring-red-500'
: 'ring-grey-300 focus:ring-indigo-600'
"
:aria-invalid="aliasSeparatorForm.errors.separator ? 'true' : undefined"
:aria-describedby="
aliasSeparatorForm.errors.separator ? 'alias-separator-error' : undefined
"
>
<option value="." class="dark:bg-grey-900">Period (.)</option>
<option value="_" class="dark:bg-grey-900">Underscore (_)</option>
<option value="-" class="dark:bg-grey-900">Hyphen (-)</option>
<option value="random" class="dark:bg-grey-900">
Random (varies per alias)
</option>
</select>
<div
v-if="aliasSeparatorForm.errors.separator"
class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-8"
>
<ExclamationCircleIcon class="h-5 w-5 text-red-500" aria-hidden="true" />
</div>
</div>
<p
v-if="aliasSeparatorForm.errors.separator"
class="mt-2 text-sm text-red-600"
id="alias-separator-error"
>
{{ aliasSeparatorForm.errors.separator }}
</p>
</div>
</div>
<button
type="submit"
:disabled="aliasSeparatorForm.processing"
class="bg-cyan-400 w-full hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:cursor-not-allowed"
>
Update Alias Separator
<loader v-if="aliasSeparatorForm.processing" />
</button>
</form>
</div>
</div>
<div class="py-10">
<div class="space-y-1">
<h3 class="text-lg font-medium leading-6 text-grey-900 dark:text-white">
@@ -580,9 +687,12 @@
</p>
<p class="text-base text-grey-700 dark:text-grey-200">
If enabled, then the <b>From:</b> header will be set as the alias email e.g.
<b>alias{{ '@' + $page.props.user.username }}.anonaddy.com</b> instead of the default
<b>alias{{ '@' + $page.props.user.username + '.' + defaultAliasDomain }}</b> instead of
the default
<b class="break-words"
>alias+sender=example.com{{ '@' + $page.props.user.username }}.anonaddy.com</b
>alias+sender=example.com{{
'@' + $page.props.user.username + '.' + defaultAliasDomain
}}</b
>
(this will be set as the Reply-To header instead)
</p>
@@ -667,7 +777,7 @@
Store Failed Deliveries
</h3>
<p class="text-base text-grey-700 dark:text-grey-200">
This setting allows you to choose whether or not addy.io should
This setting allows you to choose whether or not this instance should
<b>temporarily store</b> failed delivery attempts, this ensures that
<b>emails are not lost</b> if they are rejected by your recipients as they can be
downloaded from the failed deliveries page. Failed deliveries are
@@ -760,7 +870,7 @@
Save Alias 'Last Used At'
</h3>
<p class="text-base text-grey-700 dark:text-grey-200">
This setting allows you to choose whether or not addy.io should save the dates for
This setting allows you to choose whether or not this instance should save the dates for
<b>last forwarded at</b>, <b>last replied at</b> and <b>last sent at</b> for your
aliases. You can view this information by hovering over the relevant count of each of
these on the
@@ -860,7 +970,7 @@
<p class="text-base text-grey-700 dark:text-grey-200">
The 'From Name' is shown when you send an email from an alias or reply anonymously to
a forwarded email. If left blank, then the email alias itself will be used as the
'From Name' e.g. "example@{{ $page.props.user.username }}.anonaddy.com".
'From Name' e.g. "example@{{ $page.props.user.username }}.{{ defaultAliasDomain }}".
</p>
<div class="text-base text-grey-700 dark:text-grey-200 my-3">
The 'From Name' that is used for an alias is determined by the following
@@ -1228,6 +1338,10 @@ const props = defineProps({
type: String,
required: true,
},
aliasSeparator: {
type: String,
required: true,
},
loginRedirect: {
type: Number,
required: true,
@@ -1345,6 +1459,10 @@ const defaultAliasFormatForm = useForm({
format: props.defaultAliasFormat,
})
const aliasSeparatorForm = useForm({
separator: props.aliasSeparator,
})
const loginRedirectForm = useForm({
redirect: props.loginRedirect,
})

View File

@@ -2,6 +2,7 @@
use App\Http\Controllers\AliasExportController;
use App\Http\Controllers\AliasImportController;
use App\Http\Controllers\AliasSeparatorController;
use App\Http\Controllers\Auth\ApiAuthenticationController;
use App\Http\Controllers\Auth\BackupCodeController;
use App\Http\Controllers\Auth\ForgotUsernameController;
@@ -153,6 +154,8 @@ Route::group([
Route::post('/default-alias-format', [DefaultAliasFormatController::class, 'update'])->name('settings.default_alias_format');
Route::post('/alias-separator', [AliasSeparatorController::class, 'update'])->name('settings.alias_separator');
Route::post('/display-from-format', [DisplayFromFormatController::class, 'update'])->name('settings.display_from_format');
Route::post('/login-redirect', [LoginRedirectController::class, 'update'])->name('settings.login_redirect');

View File

@@ -257,8 +257,61 @@ class AliasesTest extends TestCase
$response->assertStatus(201);
$this->assertCount(1, $this->user->aliases);
$this->assertNotEquals($this->user->aliases[0]->id, $response->getData()->data->local_part);
$localPart = $response->getData()->data->local_part;
$this->assertNotEquals($this->user->aliases[0]->id, $localPart);
$this->assertNotEquals($this->user->aliases[0]->id, $this->user->aliases[0]->local_part);
$this->assertMatchesRegularExpression('/^[a-z]+[._-][a-z]+\d{1,3}$/', $localPart);
}
#[Test]
public function user_can_generate_new_random_male_name_alias()
{
$response = $this->json('POST', '/api/v1/aliases', [
'domain' => 'anonaddy.me',
'description' => 'the description',
'format' => 'random_male_name',
]);
$response->assertStatus(201);
$this->assertCount(1, $this->user->aliases);
$localPart = $response->getData()->data->local_part;
$this->assertNotEquals($this->user->aliases[0]->id, $localPart);
$this->assertNotEquals($this->user->aliases[0]->id, $this->user->aliases[0]->local_part);
$this->assertMatchesRegularExpression('/^[a-z]+[._-][a-z]+\d{1,3}$/', $localPart);
}
#[Test]
public function user_can_generate_new_random_female_name_alias()
{
$response = $this->json('POST', '/api/v1/aliases', [
'domain' => 'anonaddy.me',
'description' => 'the description',
'format' => 'random_female_name',
]);
$response->assertStatus(201);
$this->assertCount(1, $this->user->aliases);
$localPart = $response->getData()->data->local_part;
$this->assertNotEquals($this->user->aliases[0]->id, $localPart);
$this->assertNotEquals($this->user->aliases[0]->id, $this->user->aliases[0]->local_part);
$this->assertMatchesRegularExpression('/^[a-z]+[._-][a-z]+\d{1,3}$/', $localPart);
}
#[Test]
public function user_can_generate_new_random_noun_alias()
{
$response = $this->json('POST', '/api/v1/aliases', [
'domain' => 'anonaddy.me',
'description' => 'the description',
'format' => 'random_noun',
]);
$response->assertStatus(201);
$this->assertCount(1, $this->user->aliases);
$localPart = $response->getData()->data->local_part;
$this->assertNotEquals($this->user->aliases[0]->id, $localPart);
$this->assertNotEquals($this->user->aliases[0]->id, $this->user->aliases[0]->local_part);
$this->assertMatchesRegularExpression('/^[a-z]+[._-][a-z]+\d{1,3}$/', $localPart);
}
#[Test]