From 94079c90f2962476c635b72b230f1797bb843006 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Jul 2026 00:03:42 +0200 Subject: [PATCH 1/2] docs(readme): refresh sponsor listings --- README.md | 173 +++++++++++++++++++++++++----------------------------- 1 file changed, 81 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index b387d87e8..91458b703 100644 --- a/README.md +++ b/README.md @@ -57,106 +57,95 @@ ## Donations ### Huge Sponsors -* [MVPS](https://www.mvps.net?ref=coolify.io) - Cheap VPS servers at the highest possible quality -* [SerpAPI](https://serpapi.com?ref=coolify.io) - Google Search API — Scrape Google and other search engines from our fast, easy, and complete API -* [Seibert Group](https://seibert.link/coolifysoftware?ref=coolify.io) - Boost productivity company-wide with AI agents like Claude Code -* [ScreenshotOne](https://screenshotone.com?ref=coolify.io) - Screenshot API for devs -* [PrivateAlps](https://privatealps.net?ref=coolify.io) - Cloud Services Provider, VPS, servers infrastructure for people who care about privacy and control +* [Context.dev](https://www.context.dev/) - Web scraping API for AI agents +* [SerpAPI](https://serpapi.com) - Google Search API — Scrape Google and other search engines from our fast, easy, and complete API. +* [MVPS](https://www.mvps.net) - Cheap VPS servers at the highest possible quality +* [ScreenshotOne](https://screenshotone.com) - Screenshot API for devs +* [PrivateAlps](https://privatealps.net) - Cloud Services Provider, VPS, servers infrastructure for people who care about privacy and control +* [Seibert Group](https://seibert.link/coolifysoftware) - Boost productivity company-wide with AI agents like Claude Code +* [Contabo](https://contabo.com/en/coolify-vps/) - Cloud VPS & dedicated servers at unbeatable prices ### Big Sponsors -* [23M](https://23m.com?ref=coolify.io) - Your experts for high-availability hosting solutions! -* [American Cloud](https://americancloud.com?ref=coolify.io) - US-based cloud infrastructure services -* [Arcjet](https://arcjet.com?ref=coolify.io) - Advanced web security and performance solutions -* [BC Direct](https://bc.direct?ref=coolify.io) - Your trusted technology consulting partner -* [Blacksmith](https://blacksmith.sh?ref=coolify.io) - Infrastructure automation platform -* [Capture.page](https://capture.page/?ref=coolify.io) - Fast & Reliable Screenshot API for Developers -* [ByteBase](https://www.bytebase.com?ref=coolify.io) - Database CI/CD and Security at Scale -* [CodeRabbit](https://coderabbit.ai?ref=coolify.io) - Cut Code Review Time & Bugs in Half -* [COMIT](https://comit.international?ref=coolify.io) - New York Times award–winning contractor -* [CompAI](https://www.trycomp.ai?ref=coolify.io) - Open source compliance automation platform -* [Convex](https://convex.link/coolify.io) - Open-source reactive database for web app developers -* [Darweb](https://darweb.nl/?ref=coolify.io) - 3D CPQ solutions for ecommerce design -* [Dataforest Cloud](https://cloud.dataforest.net/en?ref=coolify.io) - Deploy cloud servers as seeds independently in seconds. Enterprise hardware, premium network, 100% made in Germany. -* [Formbricks](https://formbricks.com?ref=coolify.io) - The open source feedback platform -* [GoldenVM](https://billing.goldenvm.com?ref=coolify.io) - Premium virtual machine hosting solutions -* [Greptile](https://www.greptile.com?ref=coolify.io) - The AI Code Reviewer +* [Cloudways](https://www.cloudways.com/en/?id=2125302) - Managed cloud hosting platform by DigitalOcean +* [ByteBase](https://www.bytebase.com) - Database CI/CD and Security at Scale +* [Ramnode](https://ramnode.com/) - High Performance Cloud VPS Hosting +* [23M](https://23m.com) - Your experts for high-availability hosting solutions! +* [Macarne](https://macarne.com) - Best IP Transit & Carrier Ethernet Solutions for Simplified Network Connectivity * [Hetzner](http://htznr.li/CoolifyXHetzner) - Server, cloud, hosting, and data center solutions -* [Hostinger](https://www.hostinger.com/vps/coolify-hosting?ref=coolify.io) - Web hosting and VPS solutions -* [JobsCollider](https://jobscollider.com/remote-jobs?ref=coolify.io) - 30,000+ remote jobs for developers -* [Juxtdigital](https://juxtdigital.com?ref=coolify.io) - Digital PR & AI Authority Building Agency -* [LiquidWeb](https://liquidweb.com?ref=coolify.io) - Premium managed hosting solutions -* [Logto](https://logto.io?ref=coolify.io) - The better identity infrastructure for developers -* [LumaDock](https://lumadock.com/vps-hosting/coolify?utm_source=coolify&utm_medium=sponsorship&utm_campaign=coolify_oss_sponsor_2026&utm_content=github_readme) - Fast and reliable virtual server hosting -* [Macarne](https://macarne.com?ref=coolify.io) - Best IP Transit & Carrier Ethernet Solutions for Simplified Network Connectivity -* [Mobb](https://vibe.mobb.ai/?ref=coolify.io) - Secure Your AI-Generated Code to Unlock Dev Productivity -* [PetroSky Cloud](https://petrosky.io?ref=coolify.io) - Open source cloud deployment solutions -* [PFGLabs](https://pfglabs.com?ref=coolify.io) - Build Real Projects with Golang -* [Ramnode](https://ramnode.com/?ref=coolify.io) - High Performance Cloud VPS Hosting -* [SaasyKit](https://saasykit.com?ref=coolify.io) - Complete SaaS starter kit for developers -* [SupaGuide](https://supa.guide?ref=coolify.io) - Your comprehensive guide to Supabase -* [Supadata AI](https://supadata.ai/?ref=coolify.io) - Scrape YouTube, web, and files. Get AI-ready, clean data -* [Syntax.fm](https://syntax.fm?ref=coolify.io) - Podcast for web developers -* [Tigris](https://www.tigrisdata.com?ref=coolify.io) - Modern developer data platform -* [Tolgee](https://tolgee.io?ref=coolify.io) - The open source localization platform -* [Ubicloud](https://www.ubicloud.com?ref=coolify.io) - Open source cloud infrastructure platform -* [VPSDime](https://vpsdime.com?ref=coolify.io) - Affordable high-performance VPS hosting solutions - +* [Logto](https://logto.io) - The better identity infrastructure for developers +* [Supadata](https://supadata.ai/) - Scrape YouTube, web, and files. Get AI-ready, clean data for your next project. +* [Tolgee](https://tolgee.io) - The open source localization platform +* [Best Consultant](https://bc.direct) - Your trusted technology consulting partner +* [ArcJet](https://arcjet.com) - Advanced web security and performance solutions +* [SupaGuide](https://supa.guide) - Your comprehensive guide to Supabase +* [CodeRabbit](https://coderabbit.ai) - Cut Code Review Time & Bugs in Half +* [Convex](https://convex.link/coolify.io) - Convex is the open-source reactive database for web app developers. +* [GoldenVM](https://billing.goldenvm.com) - Premium virtual machine hosting solutions +* [Comit International](https://comit.international) - New York Times award–winning contractor! +* [Compai](https://www.trycomp.ai) - The open source compliance automation platform that does everything you need to get compliant, fast. Open source alternative to Drata & Vanta. +* [Tigris](https://www.tigrisdata.com) - Modern S3 Alternative +* [Blacksmith](https://blacksmith.sh) - Infrastructure automation platform +* [JobsCollider](https://jobscollider.com/remote-jobs) - 30,000+ remote jobs for developers +* [Darweb](https://darweb.nl/?ref=coolify.io&utm_source=coolify.io) - Design. Develop. Deliver. Specialized in 3D CPQ Solutions for eCommerce. +* [Hostinger](https://www.hostinger.com/vps/coolify-hosting) - Web hosting and VPS solutions +* [Mobb](https://vibe.mobb.ai/) - Secure Your AI-Generated Code to Unlock Dev Productivity +* [Ubicloud](https://www.ubicloud.com) - Open source cloud infrastructure platform +* [PFGLabs](https://pfglabs.com) - Build Real Projects with Golang +* [JuxtDigital](https://juxtdigital.com) - Digital PR & AI Authority Building Agency +* [SaasyKit](https://saasykit.com) - Complete SaaS starter kit for developers +* [American Cloud](https://americancloud.com) - US-based cloud infrastructure services +* [LiquidWeb](https://liquidweb.com) - Premium managed hosting solutions +* [Greptile](https://www.greptile.com) - The AI Code Reviewer +* [VPSDime](https://vpsdime.com/) - Cheap VPS Hosting - 4GB for $5/month +* [dataforest Cloud](https://cloud.dataforest.net/en) - Deploy cloud servers as seeds independently in seconds. Enterprise hardware, premium network, 100% made in Germany. +* [ISHosting](https://ishosting.com/) - Hosting and VPS solutions +* [PetroSky Cloud](https://petrosky.io) - Open source cloud deployment solutions +* [QuickSrv](https://quicksrv.io/) - Fast and reliable server hosting ### Small Sponsors -OpenElements -XamanApp -UXWizz -Evercam -Imre Ujlaki -jyc.dev -TheRealJP -360Creators -NiftyCo -Dry Software -Lightspeed.run -LinkDr -Gravity Wiz -BitLaunch -Best for Android -Ilias Ism -Formbricks -Server Searcher -Reshot -Cirun -Typebot -Creating Coding Careers -Internet Garden -Web3 Jobs -Codext -Michael Mazurczak -Fider -Flint -Paweł Pierścionek -RunPod -DartNode -Tyler Whitesides -Aquarela -Crypto Jobs List -Alfred Nutile -Startup Fame -Younes Barrad -Jonas Jaeger -Pixel Infinito -Corentin Clichy -Thompson Edolo -Devhuset -Arvensis Systems -Niklas Lausch -Cap-go -InterviewPal -Transcript LOL +Movavi +ABXY +LaunchFast Boilerplates +Vanaways +Netrouting +MindEd Tech YouStable -MindedTech -NetRouting -ParsecPH - +Transcript LOL +Autom +HuntAPI +ULTRASERVERS +VibeTone +Piloterr +Alexey Panteleev +SummYT - YouTube Summarizer +OpenElements +Xaman +Monadical +Magic as a Service +FiveManage +Crypto Jobs List +SerpAPI +typebot +360Creators +Cap-go +Cirun +Puls Digital Group +Jonathan Pereira +Internet Garden +Evercam +Web3 Jobs +LinkDr +Arvensis Systems +Reshot +RunPod +Gravity Wiz +UXWizz +Codext +InterviewPal +Decidable +Host Havoc ...and many more at [GitHub Sponsors](https://github.com/sponsors/coollabsio) From b0f0f7d8d03e6e5e3a6a3d0d98eb5825042cbe0f Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:42:52 +0200 Subject: [PATCH 2/2] feat: harden auth flows and server mobile navigation Add normalized email identity rate limiting for registration and forgot-password requests, and refresh Sentinel status from restart broadcasts. Rework server sidebars and navbar for mobile menus and active status visibility. --- app/Actions/Fortify/CreateNewUser.php | 53 ++++ app/Livewire/Server/Navbar.php | 10 + app/Providers/FortifyServiceProvider.php | 14 +- bootstrap/helpers/email.php | 20 ++ .../resources/breadcrumbs.blade.php | 2 +- .../components/server/sidebar-proxy.blade.php | 153 +++++++++-- .../server/sidebar-security.blade.php | 135 +++++++++- .../server/sidebar-sentinel.blade.php | 127 ++++++++- .../views/components/server/sidebar.blade.php | 245 ++++++++++++++---- .../application/configuration.blade.php | 2 +- .../project/database/configuration.blade.php | 2 +- .../project/service/configuration.blade.php | 2 +- .../service/database-backups.blade.php | 2 +- .../livewire/project/service/index.blade.php | 2 +- .../views/livewire/server/advanced.blade.php | 4 +- .../server/ca-certificate/show.blade.php | 2 +- .../views/livewire/server/charts.blade.php | 2 +- .../cloud-provider-token/show.blade.php | 2 +- .../server/cloudflare-tunnel.blade.php | 2 +- .../views/livewire/server/delete.blade.php | 2 +- .../livewire/server/destinations.blade.php | 2 +- .../livewire/server/docker-cleanup.blade.php | 2 +- .../livewire/server/log-drains.blade.php | 2 +- .../views/livewire/server/navbar.blade.php | 79 +++++- .../server/private-key/show.blade.php | 2 +- .../proxy/dynamic-configurations.blade.php | 2 +- .../livewire/server/proxy/logs.blade.php | 2 +- .../livewire/server/proxy/show.blade.php | 2 +- .../views/livewire/server/resources.blade.php | 2 +- .../server/security/patches.blade.php | 2 +- .../server/security/terminal-access.blade.php | 4 +- .../livewire/server/sentinel/logs.blade.php | 2 +- .../livewire/server/sentinel/show.blade.php | 2 +- .../views/livewire/server/show.blade.php | 2 +- .../views/livewire/server/swarm.blade.php | 2 +- tests/Feature/ForgotPasswordRateLimitTest.php | 48 ++++ tests/Feature/MobileResourceMenuTest.php | 103 ++++++++ tests/Feature/RegistrationRateLimitTest.php | 72 +++++ .../Feature/SentinelPushDeduplicationTest.php | 13 +- .../ServerNavbarStatusVisibilityTest.php | 29 +++ tests/Unit/EmailIdentityHelperTest.php | 16 ++ tests/Unit/ServerHeaderLayoutTest.php | 19 ++ 42 files changed, 1064 insertions(+), 128 deletions(-) create mode 100644 bootstrap/helpers/email.php create mode 100644 tests/Feature/ForgotPasswordRateLimitTest.php create mode 100644 tests/Feature/RegistrationRateLimitTest.php create mode 100644 tests/Unit/EmailIdentityHelperTest.php create mode 100644 tests/Unit/ServerHeaderLayoutTest.php diff --git a/app/Actions/Fortify/CreateNewUser.php b/app/Actions/Fortify/CreateNewUser.php index cddf66389..44a03c17d 100644 --- a/app/Actions/Fortify/CreateNewUser.php +++ b/app/Actions/Fortify/CreateNewUser.php @@ -4,7 +4,9 @@ use App\Models\Team; use App\Models\User; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\Validator; use Illuminate\Validation\Rule; use Illuminate\Validation\Rules\Password; @@ -12,6 +14,16 @@ class CreateNewUser implements CreatesNewUsers { + private const REGISTRATION_IP_MAX_ATTEMPTS = 3; + + private const REGISTRATION_IP_DECAY_SECONDS = 600; + + private const REGISTRATION_EMAIL_IDENTITY_MAX_ATTEMPTS = 3; + + private const REGISTRATION_EMAIL_IDENTITY_DECAY_SECONDS = 3600; + + public function __construct(private readonly Request $request) {} + /** * Validate and create a newly registered user. * @@ -23,6 +35,9 @@ public function create(array $input): User if (! $settings->is_registration_enabled) { abort(403); } + + $this->ensureRegistrationIsNotRateLimited($input); + Validator::make($input, [ 'name' => ['required', 'string', 'max:255'], 'email' => [ @@ -72,4 +87,42 @@ public function create(array $input): User return $user; } + + /** + * @param array $input + */ + private function ensureRegistrationIsNotRateLimited(array $input): void + { + $keys = [ + [ + 'key' => 'registration:ip:'.sha1($this->realIp()), + 'max' => self::REGISTRATION_IP_MAX_ATTEMPTS, + 'decay' => self::REGISTRATION_IP_DECAY_SECONDS, + ], + ]; + + $emailIdentity = normalize_email_identity($input['email'] ?? null); + if ($emailIdentity !== null) { + $keys[] = [ + 'key' => 'registration:email-identity:'.sha1($emailIdentity), + 'max' => self::REGISTRATION_EMAIL_IDENTITY_MAX_ATTEMPTS, + 'decay' => self::REGISTRATION_EMAIL_IDENTITY_DECAY_SECONDS, + ]; + } + + foreach ($keys as $limit) { + if (RateLimiter::tooManyAttempts($limit['key'], $limit['max'])) { + abort(429, 'Too many registration attempts. Please try again later.'); + } + } + + foreach ($keys as $limit) { + RateLimiter::hit($limit['key'], $limit['decay']); + } + } + + private function realIp(): string + { + return $this->request->server('REMOTE_ADDR') ?? $this->request->ip(); + } } diff --git a/app/Livewire/Server/Navbar.php b/app/Livewire/Server/Navbar.php index cd9cfcba6..73c256cbe 100644 --- a/app/Livewire/Server/Navbar.php +++ b/app/Livewire/Server/Navbar.php @@ -39,6 +39,7 @@ public function getListeners() return [ 'refreshServerShow' => 'refreshServer', "echo-private:team.{$teamId},ProxyStatusChangedUI" => 'showNotification', + "echo-private:team.{$teamId},SentinelRestarted" => 'refreshSentinelStatus', ]; } @@ -203,6 +204,15 @@ public function refreshServer() $this->server->load('settings'); } + public function refreshSentinelStatus($event = null): void + { + if (isset($event['serverUuid']) && $event['serverUuid'] !== $this->server->uuid) { + return; + } + + $this->refreshServer(); + } + /** * Check if Traefik has any outdated version info (patch or minor upgrade). * This shows a warning indicator in the navbar. diff --git a/app/Providers/FortifyServiceProvider.php b/app/Providers/FortifyServiceProvider.php index 85f38b967..1b201fb3f 100644 --- a/app/Providers/FortifyServiceProvider.php +++ b/app/Providers/FortifyServiceProvider.php @@ -7,6 +7,7 @@ use App\Actions\Fortify\UpdateUserPassword; use App\Actions\Fortify\UpdateUserProfileInformation; use App\Models\OauthSetting; +use App\Models\TeamInvitation; use App\Models\User; use Illuminate\Cache\RateLimiting\Limit; use Illuminate\Http\Request; @@ -82,7 +83,7 @@ public function boot(): void $user->save(); // Check if user has a pending invitation they haven't accepted yet - $invitation = \App\Models\TeamInvitation::whereEmail($email)->first(); + $invitation = TeamInvitation::whereEmail($email)->first(); if ($invitation && $invitation->isValid()) { // User is logging in for the first time after being invited // Attach them to the invited team if not already attached @@ -130,7 +131,16 @@ public function boot(): void // Use real client IP (not spoofable forwarded headers) $realIp = $request->server('REMOTE_ADDR') ?? $request->ip(); - return Limit::perMinute(5)->by($realIp); + $limits = [ + Limit::perMinutes(10, 3)->by('forgot-password:ip:'.sha1($realIp)), + ]; + + $emailIdentity = normalize_email_identity($request->input('email')); + if ($emailIdentity !== null) { + $limits[] = Limit::perHour(3)->by('forgot-password:email-identity:'.sha1($emailIdentity)); + } + + return $limits; }); RateLimiter::for('login', function (Request $request) { diff --git a/bootstrap/helpers/email.php b/bootstrap/helpers/email.php new file mode 100644 index 000000000..a0b8ba67f --- /dev/null +++ b/bootstrap/helpers/email.php @@ -0,0 +1,20 @@ +
- - - Configuration - - @if ($server->proxySet()) - - Dynamic Configurations - - - Logs - - @endif +@php + $serverPageItems = [ + [ + 'label' => 'Configuration', + 'route' => 'server.show', + 'active' => request()->routeIs('server.show', 'server.advanced', 'server.private-key', 'server.cloud-provider-token', 'server.ca-certificate', 'server.cloudflare-tunnel', 'server.docker-cleanup', 'server.destinations', 'server.log-drains', 'server.metrics', 'server.swarm', 'server.delete'), + ], + [ + 'label' => 'Proxy', + 'route' => 'server.proxy', + 'active' => request()->routeIs('server.proxy', 'server.proxy.*'), + 'visible' => ! $server->isSwarmWorker() && ! $server->settings->is_build_server, + ], + [ + 'label' => 'Sentinel', + 'route' => 'server.sentinel', + 'active' => request()->routeIs('server.sentinel', 'server.sentinel.*'), + 'visible' => $server->isFunctional() && ! $server->isSwarm() && ! $server->settings->is_build_server && auth()->user()?->can('viewSentinel', $server), + ], + [ + 'label' => 'Resources', + 'route' => 'server.resources', + 'active' => request()->routeIs('server.resources'), + ], + [ + 'label' => 'Terminal', + 'route' => 'server.command', + 'active' => request()->routeIs('server.command'), + 'navigate' => false, + 'visible' => auth()->user()?->can('canAccessTerminal'), + ], + [ + 'label' => 'Security', + 'route' => 'server.security.patches', + 'active' => request()->routeIs('server.security.patches'), + 'visible' => auth()->user()?->can('update', $server), + ], + ]; + $proxyMenuItems = [ + [ + 'label' => 'Configuration', + 'route' => 'server.proxy', + 'active' => request()->routeIs('server.proxy'), + ], + [ + 'label' => 'Dynamic Configurations', + 'route' => 'server.proxy.dynamic-confs', + 'active' => request()->routeIs('server.proxy.dynamic-confs'), + 'visible' => $server->proxySet(), + ], + [ + 'label' => 'Logs', + 'route' => 'server.proxy.logs', + 'active' => request()->routeIs('server.proxy.logs'), + 'visible' => $server->proxySet(), + 'navigate' => false, + ], + ]; + + $serverPageItems = array_values(array_filter( + $serverPageItems, + fn (array $item): bool => $item['visible'] ?? true, + )); + $proxyMenuItems = array_values(array_filter( + $proxyMenuItems, + fn (array $item): bool => $item['visible'] ?? true, + )); + $activeProxyMenuItem = collect($proxyMenuItems)->firstWhere('active', true) ?? $proxyMenuItems[0]; + $activeProxyMenuValue = (($activeProxyMenuItem['navigate'] ?? true) ? 'navigate' : 'location').'|proxy|'.route($activeProxyMenuItem['route'], $parameters); +@endphp + +
+
+ + +
+ +
diff --git a/resources/views/components/server/sidebar-security.blade.php b/resources/views/components/server/sidebar-security.blade.php index e61d23c89..9e1071854 100644 --- a/resources/views/components/server/sidebar-security.blade.php +++ b/resources/views/components/server/sidebar-security.blade.php @@ -1,10 +1,127 @@ -