diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8640797..d024d09 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
variables:
ROCKY_8_IMAGE_VERSION: 20241113_143521_update_php_82
ROCKY_9_IMAGE_VERSION: 20241114_161138_remove_redis
- DEBIAN_12_IMAGE_VERSION: 20241112_113948_update_package_and_dependencies
+ DEBIAN_12_IMAGE_VERSION: 20241204_162237_update_download_linphone_org
PHP_REDIS_REMI_VERSION: php-pecl-redis6-6.1.0-1
PHP_IGBINARY_REMI_VERSION: php-pecl-igbinary-3.2.16-2
PHP_MSGPACK_REMI_VERSION: php-pecl-msgpack-2.2.0-3
diff --git a/flexiapi/.env.example b/flexiapi/.env.example
index 126bb44..eb45339 100644
--- a/flexiapi/.env.example
+++ b/flexiapi/.env.example
@@ -45,6 +45,7 @@ APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES=10
APP_RECOVERY_CODE_EXPIRATION_MINUTES=10
APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES=0
APP_API_KEY_EXPIRATION_MINUTES=60 # Number of minutes the unused API Keys are valid
+APP_RESET_PASSWORD_EMAIL_TOKEN_EXPIRATION_MINUTES=1440 # 24h
# Account creation and authentication
ACCOUNT_EMAIL_UNIQUE=false # Emails are unique between all the accounts
diff --git a/flexiapi/app/Account.php b/flexiapi/app/Account.php
index 6e0e6ab..a3b055e 100644
--- a/flexiapi/app/Account.php
+++ b/flexiapi/app/Account.php
@@ -256,6 +256,11 @@ class Account extends Authenticatable
return $this->hasMany(AuthToken::class);
}
+ public function resetPasswordEmailTokens()
+ {
+ return $this->hasMany(ResetPasswordEmailToken::class)->latest();
+ }
+
/**
* Attributes
*/
diff --git a/flexiapi/app/Consommable.php b/flexiapi/app/Consommable.php
index d52d0b5..f54df88 100644
--- a/flexiapi/app/Consommable.php
+++ b/flexiapi/app/Consommable.php
@@ -27,6 +27,11 @@ abstract class Consommable extends Model
$this->user_agent = $request->userAgent();
}
+ public function offed(): bool
+ {
+ return $this->consumed() || $this->expired();
+ }
+
public function consumed(): bool
{
return $this->{$this->consommableAttribute} == null;
diff --git a/flexiapi/app/Http/Controllers/Account/ResetPasswordEmailController.php b/flexiapi/app/Http/Controllers/Account/ResetPasswordEmailController.php
new file mode 100644
index 0000000..bad748a
--- /dev/null
+++ b/flexiapi/app/Http/Controllers/Account/ResetPasswordEmailController.php
@@ -0,0 +1,38 @@
+firstOrFail();
+
+ return view('account.password_reset', [
+ 'token' => $token
+ ]);
+ }
+
+ public function reset(Request $request)
+ {
+ $request->validate([
+ 'token' => 'required|size:16',
+ 'password' => 'required|min:8|confirmed',
+ 'h-captcha-response' => captchaConfigured() ? 'required|HCaptcha' : ''
+ ]);
+
+ $token = ResetPasswordEmailToken::where('token', $request->get('token'))->firstOrFail();
+
+ if ($token->offed()) abort(403);
+
+ $token->account->updatePassword($request->get('password'));
+ $token->consume();
+
+ return view('account.password_changed');
+ }
+}
diff --git a/flexiapi/app/Http/Controllers/Admin/ResetPasswordEmailController.php b/flexiapi/app/Http/Controllers/Admin/ResetPasswordEmailController.php
new file mode 100644
index 0000000..ac56aba
--- /dev/null
+++ b/flexiapi/app/Http/Controllers/Admin/ResetPasswordEmailController.php
@@ -0,0 +1,38 @@
+ $account
+ ]);
+ }
+
+ public function send(int $accountId)
+ {
+ $account = Account::findOrFail($accountId);
+
+ $resetPasswordEmail = new ResetPasswordEmailToken;
+ $resetPasswordEmail->account_id = $account->id;
+ $resetPasswordEmail->token = Str::random(16);
+ $resetPasswordEmail->email = $account->email;
+ $resetPasswordEmail->save();
+
+ Mail::to($account)->send(new ResetPassword($resetPasswordEmail));
+
+ return redirect()->route('admin.account.activity.index', $account);
+ }
+}
diff --git a/flexiapi/app/Http/Kernel.php b/flexiapi/app/Http/Kernel.php
index 87075b4..4f5c78a 100644
--- a/flexiapi/app/Http/Kernel.php
+++ b/flexiapi/app/Http/Kernel.php
@@ -35,8 +35,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
- \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
- \App\Http\Middleware\Space::class
+ \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
];
/**
@@ -59,8 +58,7 @@ class Kernel extends HttpKernel
'throttle:600,1', // move to 600 instead of 60
'bindings',
'validate_json',
- 'localization',
- 'space'
+ 'localization'
],
];
@@ -89,7 +87,6 @@ class Kernel extends HttpKernel
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
- 'space' => \App\Http\Middleware\Space::class,
'space.expired' => \App\Http\Middleware\IsSpaceExpired::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
diff --git a/flexiapi/app/Http/Middleware/IsSpaceExpired.php b/flexiapi/app/Http/Middleware/IsSpaceExpired.php
index 446db97..9fae621 100644
--- a/flexiapi/app/Http/Middleware/IsSpaceExpired.php
+++ b/flexiapi/app/Http/Middleware/IsSpaceExpired.php
@@ -4,16 +4,34 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Config;
use Symfony\Component\HttpFoundation\Response;
class IsSpaceExpired
{
public function handle(Request $request, Closure $next): Response
{
- if ($request->user() && !$request->user()->superAdmin && $request->get('resolvedSpace')?->isExpired()) {
- abort(403, 'The related Space has expired');
+ if (empty(config('app.root_domain'))) {
+ return abort(503, 'APP_ROOT_DOMAIN is not configured');
}
- return $next($request);
+ $space = \App\Space::where('host', $request->header('host'))->first();
+
+ if ($space) {
+ if (!str_ends_with($space->host, config('app.root_domain'))) {
+ return abort(503, 'The APP_ROOT_DOMAIN configured does not match with the current root domain');
+ }
+
+ Config::set('app.url', '://' . $space->host);
+ Config::set('app.sip_domain', $space->domain);
+
+ if ($request->user() && !$request->user()->superAdmin && $space?->isExpired()) {
+ abort(403, 'The related Space has expired');
+ }
+
+ return $next($request);
+ }
+
+ return abort(404, 'Host not configured');
}
}
diff --git a/flexiapi/app/Http/Middleware/Space.php b/flexiapi/app/Http/Middleware/Space.php
deleted file mode 100644
index 1c77c7c..0000000
--- a/flexiapi/app/Http/Middleware/Space.php
+++ /dev/null
@@ -1,35 +0,0 @@
-header('host'))->first();
-
- if ($space) {
- if (!str_ends_with($space->host, config('app.root_domain'))) {
- return abort(503, 'The APP_ROOT_DOMAIN configured does not match with the current root domain');
- }
-
- Config::set('app.url', '://' . $space->host);
- Config::set('app.sip_domain', $space->domain);
-
- $request->request->set('resolvedSpace', $space);
-
- return $next($request);
- }
-
- return abort(404, 'Host not configured');
- }
-}
diff --git a/flexiapi/app/Mail/ResetPassword.php b/flexiapi/app/Mail/ResetPassword.php
new file mode 100644
index 0000000..c68110d
--- /dev/null
+++ b/flexiapi/app/Mail/ResetPassword.php
@@ -0,0 +1,48 @@
+.
+*/
+
+namespace App\Mail;
+
+use Illuminate\Bus\Queueable;
+use Illuminate\Mail\Mailable;
+use Illuminate\Queue\SerializesModels;
+
+use App\Account;
+use App\ResetPasswordEmailToken;
+
+class ResetPassword extends Mailable
+{
+ use Queueable, SerializesModels;
+
+ private $token;
+
+ public function __construct(ResetPasswordEmailToken $token)
+ {
+ $this->token = $token;
+ }
+
+ public function build()
+ {
+ return $this->view('mails.reset_password')
+ ->text('mails.reset_password')
+ ->with([
+ 'token' => $this->token
+ ]);
+ }
+}
diff --git a/flexiapi/app/ResetPasswordEmailToken.php b/flexiapi/app/ResetPasswordEmailToken.php
new file mode 100644
index 0000000..10241d9
--- /dev/null
+++ b/flexiapi/app/ResetPasswordEmailToken.php
@@ -0,0 +1,28 @@
+belongsTo(Account::class);
+ }
+
+ public function consume()
+ {
+ $this->used = true;
+ $this->save();
+ }
+
+ public function consumed(): bool
+ {
+ return $this->used == true;
+ }
+}
diff --git a/flexiapi/composer.lock b/flexiapi/composer.lock
index a2f95b1..0e1e305 100644
--- a/flexiapi/composer.lock
+++ b/flexiapi/composer.lock
@@ -1325,16 +1325,16 @@
},
{
"name": "giggsey/libphonenumber-for-php-lite",
- "version": "8.13.50",
+ "version": "8.13.51",
"source": {
"type": "git",
"url": "https://github.com/giggsey/libphonenumber-for-php-lite.git",
- "reference": "57bb2bfd8d4a9896ed961c584141247f2a35bc04"
+ "reference": "34e43f33e21a8cdeebc36e9de57157ae821ef56b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/57bb2bfd8d4a9896ed961c584141247f2a35bc04",
- "reference": "57bb2bfd8d4a9896ed961c584141247f2a35bc04",
+ "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php-lite/zipball/34e43f33e21a8cdeebc36e9de57157ae821ef56b",
+ "reference": "34e43f33e21a8cdeebc36e9de57157ae821ef56b",
"shasum": ""
},
"require": {
@@ -1404,7 +1404,7 @@
"issues": "https://github.com/giggsey/libphonenumber-for-php-lite/issues",
"source": "https://github.com/giggsey/libphonenumber-for-php-lite"
},
- "time": "2024-11-18T09:58:30+00:00"
+ "time": "2024-12-02T09:22:48+00:00"
},
{
"name": "graham-campbell/result-type",
@@ -4790,16 +4790,16 @@
},
{
"name": "psy/psysh",
- "version": "v0.12.4",
+ "version": "v0.12.5",
"source": {
"type": "git",
"url": "https://github.com/bobthecow/psysh.git",
- "reference": "2fd717afa05341b4f8152547f142cd2f130f6818"
+ "reference": "36a03ff27986682c22985e56aabaf840dd173cb5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/bobthecow/psysh/zipball/2fd717afa05341b4f8152547f142cd2f130f6818",
- "reference": "2fd717afa05341b4f8152547f142cd2f130f6818",
+ "url": "https://api.github.com/repos/bobthecow/psysh/zipball/36a03ff27986682c22985e56aabaf840dd173cb5",
+ "reference": "36a03ff27986682c22985e56aabaf840dd173cb5",
"shasum": ""
},
"require": {
@@ -4826,12 +4826,12 @@
],
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "0.12.x-dev"
- },
"bamarni-bin": {
"bin-links": false,
"forward-command": false
+ },
+ "branch-alias": {
+ "dev-main": "0.12.x-dev"
}
},
"autoload": {
@@ -4863,9 +4863,9 @@
],
"support": {
"issues": "https://github.com/bobthecow/psysh/issues",
- "source": "https://github.com/bobthecow/psysh/tree/v0.12.4"
+ "source": "https://github.com/bobthecow/psysh/tree/v0.12.5"
},
- "time": "2024-06-10T01:18:23+00:00"
+ "time": "2024-11-29T06:14:30+00:00"
},
{
"name": "ralouphie/getallheaders",
@@ -5599,16 +5599,16 @@
},
{
"name": "respect/validation",
- "version": "2.3.8",
+ "version": "2.3.9",
"source": {
"type": "git",
"url": "https://github.com/Respect/Validation.git",
- "reference": "25ce44c7ee9613d260c7c0e44e27daa2131f383a"
+ "reference": "c96758eb27339c97486f311f25fbc797df2f6736"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Respect/Validation/zipball/25ce44c7ee9613d260c7c0e44e27daa2131f383a",
- "reference": "25ce44c7ee9613d260c7c0e44e27daa2131f383a",
+ "url": "https://api.github.com/repos/Respect/Validation/zipball/c96758eb27339c97486f311f25fbc797df2f6736",
+ "reference": "c96758eb27339c97486f311f25fbc797df2f6736",
"shasum": ""
},
"require": {
@@ -5661,9 +5661,9 @@
],
"support": {
"issues": "https://github.com/Respect/Validation/issues",
- "source": "https://github.com/Respect/Validation/tree/2.3.8"
+ "source": "https://github.com/Respect/Validation/tree/2.3.9"
},
- "time": "2024-11-26T09:14:36+00:00"
+ "time": "2024-11-28T09:44:01+00:00"
},
{
"name": "sabre/uri",
@@ -5922,12 +5922,12 @@
"type": "library",
"extra": {
"laravel": {
- "providers": [
- "Scyllaly\\HCaptcha\\HCaptchaServiceProvider"
- ],
"aliases": {
"HCaptcha": "Scyllaly\\HCaptcha\\Facades\\HCaptcha"
- }
+ },
+ "providers": [
+ "Scyllaly\\HCaptcha\\HCaptchaServiceProvider"
+ ]
}
},
"autoload": {
@@ -7034,16 +7034,16 @@
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@@ -7081,7 +7081,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -7097,7 +7097,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/error-handler",
@@ -7256,16 +7256,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50"
+ "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50",
- "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f",
+ "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f",
"shasum": ""
},
"require": {
@@ -7312,7 +7312,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -7328,7 +7328,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/finder",
@@ -7396,16 +7396,16 @@
},
{
"name": "symfony/http-foundation",
- "version": "v6.4.15",
+ "version": "v6.4.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6"
+ "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6",
- "reference": "9b3165eb2f04aeaa1a5a2cfef73e63fe3b22dff6",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/431771b7a6f662f1575b3cfc8fd7617aa9864d57",
+ "reference": "431771b7a6f662f1575b3cfc8fd7617aa9864d57",
"shasum": ""
},
"require": {
@@ -7453,7 +7453,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v6.4.15"
+ "source": "https://github.com/symfony/http-foundation/tree/v6.4.16"
},
"funding": [
{
@@ -7469,20 +7469,20 @@
"type": "tidelift"
}
],
- "time": "2024-11-08T16:09:24+00:00"
+ "time": "2024-11-13T18:58:10+00:00"
},
{
"name": "symfony/http-kernel",
- "version": "v6.4.15",
+ "version": "v6.4.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
- "reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5"
+ "reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b002a5b3947653c5aee3adac2a024ea615fd3ff5",
- "reference": "b002a5b3947653c5aee3adac2a024ea615fd3ff5",
+ "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8838b5b21d807923b893ccbfc2cbeda0f1bc00f0",
+ "reference": "8838b5b21d807923b893ccbfc2cbeda0f1bc00f0",
"shasum": ""
},
"require": {
@@ -7567,7 +7567,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-kernel/tree/v6.4.15"
+ "source": "https://github.com/symfony/http-kernel/tree/v6.4.16"
},
"funding": [
{
@@ -7583,7 +7583,7 @@
"type": "tidelift"
}
],
- "time": "2024-11-13T13:57:37+00:00"
+ "time": "2024-11-27T12:49:36+00:00"
},
{
"name": "symfony/mailer",
@@ -8449,16 +8449,16 @@
},
{
"name": "symfony/routing",
- "version": "v6.4.13",
+ "version": "v6.4.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
- "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278"
+ "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278",
- "reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278",
+ "url": "https://api.github.com/repos/symfony/routing/zipball/91e02e606b4b705c2f4fb42f7e7708b7923a3220",
+ "reference": "91e02e606b4b705c2f4fb42f7e7708b7923a3220",
"shasum": ""
},
"require": {
@@ -8512,7 +8512,7 @@
"url"
],
"support": {
- "source": "https://github.com/symfony/routing/tree/v6.4.13"
+ "source": "https://github.com/symfony/routing/tree/v6.4.16"
},
"funding": [
{
@@ -8528,20 +8528,20 @@
"type": "tidelift"
}
],
- "time": "2024-10-01T08:30:56+00:00"
+ "time": "2024-11-13T15:31:34+00:00"
},
{
"name": "symfony/service-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"shasum": ""
},
"require": {
@@ -8595,7 +8595,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -8611,7 +8611,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/string",
@@ -8796,16 +8796,16 @@
},
{
"name": "symfony/translation-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a"
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
- "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c",
+ "reference": "4667ff3bd513750603a09c8dedbea942487fb07c",
"shasum": ""
},
"require": {
@@ -8854,7 +8854,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -8870,7 +8870,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/uid",
@@ -10101,16 +10101,16 @@
},
{
"name": "symfony/dependency-injection",
- "version": "v6.4.15",
+ "version": "v6.4.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
- "reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36"
+ "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/70ab1f65a4516ef741e519ea938e6aa465e6aa36",
- "reference": "70ab1f65a4516ef741e519ea938e6aa465e6aa36",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/7a379d8871f6a36f01559c14e11141cc02eb8dc8",
+ "reference": "7a379d8871f6a36f01559c14e11141cc02eb8dc8",
"shasum": ""
},
"require": {
@@ -10162,7 +10162,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/dependency-injection/tree/v6.4.15"
+ "source": "https://github.com/symfony/dependency-injection/tree/v6.4.16"
},
"funding": [
{
@@ -10178,7 +10178,7 @@
"type": "tidelift"
}
],
- "time": "2024-11-09T06:56:25+00:00"
+ "time": "2024-11-25T14:52:46+00:00"
},
{
"name": "symfony/filesystem",
diff --git a/flexiapi/config/app.php b/flexiapi/config/app.php
index 7a03c3b..4a79f0e 100644
--- a/flexiapi/config/app.php
+++ b/flexiapi/config/app.php
@@ -52,6 +52,7 @@ return [
'phone_change_code_expiration_minutes' => env('APP_PHONE_CHANGE_CODE_EXPIRATION_MINUTES', 10),
'recovery_code_expiration_minutes' => env('APP_RECOVERY_CODE_EXPIRATION_MINUTES', 10),
'provisioning_token_expiration_minutes' => env('APP_PROVISIONING_TOKEN_EXPIRATION_MINUTES', 0),
+ 'reset_password_email_token_expiration_minutes' => env('APP_RESET_PASSWORD_EMAIL_TOKEN_EXPIRATION_MINUTES', 1440),
/**
* Amount of minutes before re-authorizing the generation of a new account creation token
*/
diff --git a/flexiapi/database/migrations/2024_12_02_142311_create_reset_password_email_tokens_table.php b/flexiapi/database/migrations/2024_12_02_142311_create_reset_password_email_tokens_table.php
new file mode 100644
index 0000000..b3f5a75
--- /dev/null
+++ b/flexiapi/database/migrations/2024_12_02_142311_create_reset_password_email_tokens_table.php
@@ -0,0 +1,30 @@
+id();
+ $table->string('token', 16);
+ $table->boolean('used')->default(false);
+ $table->string('email');
+ $table->integer('account_id')->unsigned();
+ $table->string('ip')->nullable();
+ $table->string('user_agent')->nullable();
+ $table->timestamps();
+
+ $table->foreign('account_id')->references('id')
+ ->on('accounts')->onDelete('cascade');
+ });
+ }
+
+ public function down(): void
+ {
+ Schema::dropIfExists('reset_password_email_tokens');
+ }
+};
diff --git a/flexiapi/public/css/style.css b/flexiapi/public/css/style.css
index 9bb9446..d4fd183 100644
--- a/flexiapi/public/css/style.css
+++ b/flexiapi/public/css/style.css
@@ -619,6 +619,7 @@ table tr td a {
table tr td,
table tr th {
+ width: 20rem;
padding: 1rem;
font-size: 1.5rem;
}
diff --git a/flexiapi/resources/views/account/password_changed.blade.php b/flexiapi/resources/views/account/password_changed.blade.php
new file mode 100644
index 0000000..21b743a
--- /dev/null
+++ b/flexiapi/resources/views/account/password_changed.blade.php
@@ -0,0 +1,18 @@
+@extends('layouts.main', ['welcome' => true])
+
+@section('content')
+ Your password was updated properly.
+ Authenticate
+ This link is not available anymore.lock Reset password
+
+
lock Reset password
+
+
| Token | +Created | +Used | +|
|---|---|---|---|
| {{ $resetPasswordEmailToken->token }} | ++ {{ $resetPasswordEmailToken->created_at }} + | ++ {{ $resetPasswordEmailToken->consumed() ? $resetPasswordEmailToken->updated_at : '-' }} + | ++ {{ $resetPasswordEmailToken->email }} + | +
+ + Send an email to the user to reset the password + +
+ @endifAn email will be sent to {{ $account->email }} with a unique link allowing the user to reset its password.
+ +This link will be available for {{ config('app.reset_password_email_token_expiration_minutes')/60 }} hours.
+ ++ + paper-plane-right Send + +
+ +@endsection \ No newline at end of file diff --git a/flexiapi/resources/views/mails/reset_password.blade.php b/flexiapi/resources/views/mails/reset_password.blade.php new file mode 100644 index 0000000..6a2780a --- /dev/null +++ b/flexiapi/resources/views/mails/reset_password.blade.php @@ -0,0 +1,21 @@ + + +Hello,
++ You are invited to reset your {{ $token->account->identifier }} account password on {{ config('app.name') }} via your email account. +
+The following link will be valid for {{ config('app.reset_password_email_token_expiration_minutes')/60 }} hours.
++ + {{ route('account.reset_password_email.change', $token->token) }} + +
+
+ Regards,
+ {{ config('mail.signature') }}
+