diff --git a/app/Notifications/SslExpirationNotification.php b/app/Notifications/SslExpirationNotification.php new file mode 100644 index 000000000..78e1e8be9 --- /dev/null +++ b/app/Notifications/SslExpirationNotification.php @@ -0,0 +1,151 @@ +onQueue('high'); + $this->resources = collect($resources); + + // Collect URLs for each resource + $this->resources->each(function ($resource) { + if (data_get($resource, 'environment.project.uuid')) { + $routeName = match ($resource->type()) { + 'application' => 'project.application.configuration', + 'database' => 'project.database.configuration', + 'service' => 'project.service.configuration', + default => null + }; + + if ($routeName) { + $route = route($routeName, [ + 'project_uuid' => data_get($resource, 'environment.project.uuid'), + 'environment_uuid' => data_get($resource, 'environment.uuid'), + $resource->type().'_uuid' => data_get($resource, 'uuid'), + ]); + + $settings = instanceSettings(); + if (data_get($settings, 'fqdn')) { + $url = Url::fromString($route); + $url = $url->withPort(null); + $fqdn = data_get($settings, 'fqdn'); + $fqdn = str_replace(['http://', 'https://'], '', $fqdn); + $url = $url->withHost($fqdn); + + $this->urls[$resource->name] = $url->__toString(); + } else { + $this->urls[$resource->name] = $route; + } + } + } + }); + } + + public function via(object $notifiable): array + { + return $notifiable->getEnabledChannels('ssl_certificate_renewal'); + } + + public function toMail(): MailMessage + { + $mail = new MailMessage; + $mail->subject('Coolify: [Action Required] SSL Certificates Renewed - Manual Redeployment Needed'); + $mail->view('emails.ssl-certificate-renewed', [ + 'resources' => $this->resources, + 'urls' => $this->urls, + ]); + + return $mail; + } + + public function toDiscord(): DiscordMessage + { + $resourceNames = $this->resources->pluck('name')->join(', '); + + $message = new DiscordMessage( + title: '🔒 SSL Certificates Renewed', + description: "SSL certificates have been renewed for: {$resourceNames}.\n\n**Action Required:** These resources need to be redeployed manually.", + color: DiscordMessage::warningColor(), + ); + + foreach ($this->urls as $name => $url) { + $message->addField($name, "[View Resource]({$url})"); + } + + return $message; + } + + public function toTelegram(): array + { + $resourceNames = $this->resources->pluck('name')->join(', '); + $message = "Coolify: SSL certificates have been renewed for: {$resourceNames}.\n\nAction Required: These resources need to be redeployed manually for the new SSL certificates to take effect."; + + $buttons = []; + foreach ($this->urls as $name => $url) { + $buttons[] = [ + 'text' => "View {$name}", + 'url' => $url, + ]; + } + + return [ + 'message' => $message, + 'buttons' => $buttons, + ]; + } + + public function toPushover(): PushoverMessage + { + $resourceNames = $this->resources->pluck('name')->join(', '); + $message = "SSL certificates have been renewed for: {$resourceNames}

"; + $message .= 'Action Required: These resources need to be redeployed manually for the new SSL certificates to take effect.'; + + $buttons = []; + foreach ($this->urls as $name => $url) { + $buttons[] = [ + 'text' => "View {$name}", + 'url' => $url, + ]; + } + + return new PushoverMessage( + title: 'SSL Certificates Renewed', + level: 'warning', + message: $message, + buttons: $buttons, + ); + } + + public function toSlack(): SlackMessage + { + $resourceNames = $this->resources->pluck('name')->join(', '); + $description = "SSL certificates have been renewed for: {$resourceNames}\n\n"; + $description .= '**Action Required:** These resources need to be redeployed manually for the new SSL certificates to take effect.'; + + if (! empty($this->urls)) { + $description .= "\n\n**Resource URLs:**\n"; + foreach ($this->urls as $name => $url) { + $description .= "• {$name}: {$url}\n"; + } + } + + return new SlackMessage( + title: '🔒 SSL Certificates Renewed', + description: $description, + color: SlackMessage::warningColor() + ); + } +} diff --git a/resources/views/emails/ssl-certificate-renewed.blade.php b/resources/views/emails/ssl-certificate-renewed.blade.php new file mode 100644 index 000000000..3d0d7a7b2 --- /dev/null +++ b/resources/views/emails/ssl-certificate-renewed.blade.php @@ -0,0 +1,28 @@ + +

SSL Certificates Renewed

+ +

SSL certificates have been renewed for the following resources:

+ + + +
+ ⚠️ Action Required: These resources need to be redeployed manually for the new SSL certificates to take effect. Please do this in the next few days to ensure your database connections remain accessible. +
+ +

The old SSL certificates will remain valid for approximately 14 more days, as we renew certificates 14 days before their expiration.

+ +@if(isset($urls) && count($urls) > 0) +
+

You can redeploy these resources here:

+ +
+@endif +