diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php
index 77ae73fce..7950bd4f7 100644
--- a/app/Actions/Fortify/CreateNewUser.php
+++ b/app/Actions/Fortify/CreateNewUser.php
@@ -58,6 +58,11 @@ class CreateNewUser implements CreatesNewUsers
'password' => Hash::make($input['password']),
]);
$team = $user->teams()->first();
+ if (isCloud()) {
+ $user->sendVerificationEmail();
+ } else {
+ $user->markEmailAsVerified();
+ }
}
// Set session variable
session(['currentTeam' => $user->currentTeam = $team]);
diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php
index be63b9694..d8cba40b6 100644
--- a/app/Http/Kernel.php
+++ b/app/Http/Kernel.php
@@ -38,8 +38,7 @@ class Kernel extends HttpKernel
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\CheckForcePasswordReset::class,
- \App\Http\Middleware\IsSubscriptionValid::class,
- \App\Http\Middleware\IsBoardingFlow::class,
+ \App\Http\Middleware\DecideWhatToDoWithUser::class,
],
diff --git a/app/Http/Livewire/Upgrade.php b/app/Http/Livewire/Upgrade.php
index d5ff62a64..ca5f7df30 100644
--- a/app/Http/Livewire/Upgrade.php
+++ b/app/Http/Livewire/Upgrade.php
@@ -5,10 +5,11 @@ namespace App\Http\Livewire;
use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use Livewire\Component;
-use Masmerise\Toaster\Toaster;
+use DanHarrin\LivewireRateLimiting\WithRateLimiting;
class Upgrade extends Component
{
+ use WithRateLimiting;
public bool $showProgress = false;
public bool $isUpgradeAvailable = false;
public string $latestVersion = '';
@@ -31,6 +32,7 @@ class Upgrade extends Component
public function upgrade()
{
try {
+ $this->rateLimit(1, 30);
if ($this->showProgress) {
return;
}
diff --git a/app/Http/Livewire/VerifyEmail.php b/app/Http/Livewire/VerifyEmail.php
new file mode 100644
index 000000000..e485102cb
--- /dev/null
+++ b/app/Http/Livewire/VerifyEmail.php
@@ -0,0 +1,26 @@
+rateLimit(1, 300);
+ auth()->user()->sendVerificationEmail();
+ $this->emit('success', 'Email verification link sent!');
+
+ } catch(\Exception $e) {
+ ray($e);
+ return handleError($e,$this);
+ }
+ }
+ public function render()
+ {
+ return view('livewire.verify-email');
+ }
+}
diff --git a/app/Http/Middleware/DecideWhatToDoWithUser.php b/app/Http/Middleware/DecideWhatToDoWithUser.php
new file mode 100644
index 000000000..a8db3a823
--- /dev/null
+++ b/app/Http/Middleware/DecideWhatToDoWithUser.php
@@ -0,0 +1,45 @@
+user() || !isCloud()) {
+ return $next($request);
+ }
+ if (!auth()->user()->hasVerifiedEmail()) {
+ if ($request->path() === 'verify' || in_array($request->path(), allowedPathsForInvalidAccounts()) || $request->routeIs('verify.verify')) {
+ return $next($request);
+ }
+ return redirect('/verify');
+ }
+ if (!isSubscriptionActive() && !isSubscriptionOnGracePeriod()) {
+ if (!in_array($request->path(), allowedPathsForUnsubscribedAccounts())) {
+ if (Str::startsWith($request->path(), 'invitations')) {
+ return $next($request);
+ }
+ return redirect('subscription');
+ }
+ }
+ if (showBoarding() && !in_array($request->path(), allowedPathsForBoardingAccounts())) {
+ if (Str::startsWith($request->path(), 'invitations')) {
+ return $next($request);
+ }
+ return redirect('boarding');
+ }
+ if (auth()->user()->hasVerifiedEmail() && $request->path() === 'verify') {
+ return redirect('/');
+ }
+ if (isSubscriptionActive() && $request->path() === 'subscription') {
+ return redirect('/');
+ }
+ return $next($request);
+ }
+}
diff --git a/app/Http/Middleware/IsBoardingFlow.php b/app/Http/Middleware/NOTUSEDIsBoardingFlow.php
similarity index 100%
rename from app/Http/Middleware/IsBoardingFlow.php
rename to app/Http/Middleware/NOTUSEDIsBoardingFlow.php
diff --git a/app/Http/Middleware/IsSubscriptionValid.php b/app/Http/Middleware/NOTUSEDIsSubscriptionValid.php
similarity index 100%
rename from app/Http/Middleware/IsSubscriptionValid.php
rename to app/Http/Middleware/NOTUSEDIsSubscriptionValid.php
diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php
index d69d95981..23ed70f8f 100644
--- a/app/Models/Subscription.php
+++ b/app/Models/Subscription.php
@@ -33,7 +33,7 @@ class Subscription extends Model
}
if (isStripe()) {
if (!$this->stripe_plan_id) {
- return 'zero';
+ return 'zero';
}
$subscription = Subscription::where('id', $this->id)->first();
if (!$subscription) {
diff --git a/app/Models/User.php b/app/Models/User.php
index aba05acf3..51ac0aa14 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -6,8 +6,12 @@ use App\Notifications\Channels\SendsEmail;
use App\Notifications\TransactionalEmails\ResetPassword as TransactionalEmailsResetPassword;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notifiable;
+use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
+use Illuminate\Support\Facades\Config;
+use Illuminate\Support\Facades\URL;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
@@ -54,6 +58,23 @@ class User extends Authenticatable implements SendsEmail
return $this->email;
}
+ public function sendVerificationEmail()
+ {
+ $mail = new MailMessage();
+ $url = Url::temporarySignedRoute(
+ 'verify.verify',
+ Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
+ [
+ 'id' => $this->getKey(),
+ 'hash' => sha1($this->getEmailForVerification()),
+ ]
+ );
+ $mail->view('emails.email-verification', [
+ 'url' => $url,
+ ]);
+ $mail->subject('Coolify Cloud: Verify your email.');
+ send_user_an_email($mail, $this->email);
+ }
public function sendPasswordResetNotification($token): void
{
$this->notify(new TransactionalEmailsResetPassword($token));
@@ -61,7 +82,7 @@ class User extends Authenticatable implements SendsEmail
public function isAdmin()
{
- return data_get($this->pivot,'role') === 'admin' || data_get($this->pivot,'role') === 'owner';
+ return data_get($this->pivot, 'role') === 'admin' || data_get($this->pivot, 'role') === 'owner';
}
public function isAdminFromSession()
@@ -79,7 +100,7 @@ class User extends Authenticatable implements SendsEmail
return true;
}
$team = $teams->where('id', session('currentTeam')->id)->first();
- $role = data_get($team,'pivot.role');
+ $role = data_get($team, 'pivot.role');
return $role === 'admin' || $role === 'owner';
}
@@ -96,7 +117,7 @@ class User extends Authenticatable implements SendsEmail
public function currentTeam()
{
- return Cache::remember('team:' . auth()->user()->id, 3600, function() {
+ return Cache::remember('team:' . auth()->user()->id, 3600, function () {
return Team::find(session('currentTeam')->id);
});
}
diff --git a/bootstrap/helpers/subscriptions.php b/bootstrap/helpers/subscriptions.php
index 9ea76ec9b..cd1f79fb4 100644
--- a/bootstrap/helpers/subscriptions.php
+++ b/bootstrap/helpers/subscriptions.php
@@ -122,14 +122,13 @@ function allowedPathsForUnsubscribedAccounts()
return [
'subscription',
'login',
- 'register',
+ 'logout',
'waitlist',
'force-password-reset',
- 'logout',
'livewire/message/force-password-reset',
'livewire/message/check-license',
'livewire/message/switch-team',
- 'livewire/message/subscription.pricing-plans'
+ 'livewire/message/subscription.pricing-plans',
];
}
function allowedPathsForBoardingAccounts()
@@ -141,3 +140,10 @@ function allowedPathsForBoardingAccounts()
'livewire/message/activity-monitor'
];
}
+function allowedPathsForInvalidAccounts() {
+ return [
+ 'logout',
+ 'verify',
+ 'livewire/message/verify-email',
+ ];
+}
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php
index 47ac188f2..d2e00f58f 100644
--- a/resources/views/auth/login.blade.php
+++ b/resources/views/auth/login.blade.php
@@ -9,12 +9,12 @@
@if ($is_registration_enabled)
@if (config('coolify.waitlist'))
+ class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
Join the waitlist
@else
+ class="text-xs text-center text-white normal-case bg-transparent border-none rounded no-animation hover:no-underline btn btn-sm bg-coollabs-gradient">
{{ __('auth.register_now') }}
@endif
diff --git a/resources/views/auth/verify-email.blade.php b/resources/views/auth/verify-email.blade.php
new file mode 100644
index 000000000..dca6a4c6a
--- /dev/null
+++ b/resources/views/auth/verify-email.blade.php
@@ -0,0 +1,12 @@
+ Verification Email Sent
+
To activate your account, please open the email and follow the
+ instructions.
+