From 5f6cdf7a71652cea5a08034f7ae8a2d30c73fafa Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 25 Apr 2025 10:25:26 +0200
Subject: [PATCH 001/282] feat(README): add InterviewPal sponsorship link and
 corresponding SVG icon
---
 README.md                    | 2 ++
 public/svgs/interviewpal.svg | 1 +
 2 files changed, 3 insertions(+)
 create mode 100644 public/svgs/interviewpal.svg
diff --git a/README.md b/README.md
index 6e245aa22..5f583df75 100644
--- a/README.md
+++ b/README.md
@@ -131,6 +131,8 @@ Thank you so much!
 
 
 
+
+
 
 ...and many more at [GitHub Sponsors](https://github.com/sponsors/coollabsio)
 
diff --git a/public/svgs/interviewpal.svg b/public/svgs/interviewpal.svg
new file mode 100644
index 000000000..f0dc3731a
--- /dev/null
+++ b/public/svgs/interviewpal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
From 2083ec1c0d5712b984b7531255689a9685d83a12 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 25 Apr 2025 10:25:54 +0200
Subject: [PATCH 002/282] chore(versions): update coolify version to
 4.0.0-beta.413 and nightly version to 4.0.0-beta.414 in configuration files
---
 config/constants.php        | 2 +-
 other/nightly/versions.json | 4 ++--
 versions.json               | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/config/constants.php b/config/constants.php
index f05bc7d8e..2790258fa 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -2,7 +2,7 @@
 
 return [
     'coolify' => [
-        'version' => '4.0.0-beta.412',
+        'version' => '4.0.0-beta.413',
         'helper_version' => '1.0.8',
         'realtime_version' => '1.0.7',
         'self_hosted' => env('SELF_HOSTED', true),
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index c3f4ba912..31e0e279d 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -1,10 +1,10 @@
 {
     "coolify": {
         "v4": {
-            "version": "4.0.0-beta.412"
+            "version": "4.0.0-beta.413"
         },
         "nightly": {
-            "version": "4.0.0-beta.413"
+            "version": "4.0.0-beta.414"
         },
         "helper": {
             "version": "1.0.8"
diff --git a/versions.json b/versions.json
index c3f4ba912..31e0e279d 100644
--- a/versions.json
+++ b/versions.json
@@ -1,10 +1,10 @@
 {
     "coolify": {
         "v4": {
-            "version": "4.0.0-beta.412"
+            "version": "4.0.0-beta.413"
         },
         "nightly": {
-            "version": "4.0.0-beta.413"
+            "version": "4.0.0-beta.414"
         },
         "helper": {
             "version": "1.0.8"
From f5cc2728618b4011bdd01d991f8eeec86d4518ab Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 25 Apr 2025 15:35:23 +0200
Subject: [PATCH 003/282] fix(terminal): enhance WebSocket client verification
 with authorized IPs in terminal server
---
 config/constants.php                       |  2 +-
 docker/coolify-realtime/terminal-server.js | 72 ++++++++++++++++++----
 routes/web.php                             | 11 ++++
 3 files changed, 72 insertions(+), 13 deletions(-)
diff --git a/config/constants.php b/config/constants.php
index 2790258fa..a849ae93e 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -4,7 +4,7 @@ return [
     'coolify' => [
         'version' => '4.0.0-beta.413',
         'helper_version' => '1.0.8',
-        'realtime_version' => '1.0.7',
+        'realtime_version' => '1.0.8',
         'self_hosted' => env('SELF_HOSTED', true),
         'autoupdate' => env('AUTOUPDATE'),
         'base_config_path' => env('BASE_CONFIG_PATH', '/data/coolify'),
diff --git a/docker/coolify-realtime/terminal-server.js b/docker/coolify-realtime/terminal-server.js
index 6649f866c..61dd29453 100755
--- a/docker/coolify-realtime/terminal-server.js
+++ b/docker/coolify-realtime/terminal-server.js
@@ -3,7 +3,9 @@ import http from 'http';
 import pty from 'node-pty';
 import axios from 'axios';
 import cookie from 'cookie';
-import 'dotenv/config'
+import 'dotenv/config';
+
+const userSessions = new Map();
 
 const server = http.createServer((req, res) => {
     if (req.url === '/ready') {
@@ -15,16 +17,20 @@ const server = http.createServer((req, res) => {
     }
 });
 
-const verifyClient = async (info, callback) => {
-    const cookies = cookie.parse(info.req.headers.cookie || '');
-    // const origin = new URL(info.origin);
-    // const protocol = origin.protocol;
+const getSessionCookie = (req) => {
+    const cookies = cookie.parse(req.headers.cookie || '');
     const xsrfToken = cookies['XSRF-TOKEN'];
-
-    // Generate session cookie name based on APP_NAME
     const appName = process.env.APP_NAME || 'laravel';
     const sessionCookieName = `${appName.replace(/[^a-zA-Z0-9]/g, '_').toLowerCase()}_session`;
-    const laravelSession = cookies[sessionCookieName];
+    return {
+        sessionCookieName,
+        xsrfToken: xsrfToken,
+        laravelSession: cookies[sessionCookieName]
+    }
+}
+
+const verifyClient = async (info, callback) => {
+    const { xsrfToken, laravelSession, sessionCookieName } = getSessionCookie(info.req);
 
     // Verify presence of required tokens
     if (!laravelSession || !xsrfToken) {
@@ -54,11 +60,24 @@ const verifyClient = async (info, callback) => {
 
 
 const wss = new WebSocketServer({ server, path: '/terminal/ws', verifyClient: verifyClient });
-const userSessions = new Map();
 
-wss.on('connection', (ws) => {
+wss.on('connection', async (ws, req) => {
     const userId = generateUserId();
-    const userSession = { ws, userId, ptyProcess: null, isActive: false };
+    const userSession = { ws, userId, ptyProcess: null, isActive: false, authorizedIPs: [] };
+    const { xsrfToken, laravelSession, sessionCookieName } = getSessionCookie(req);
+
+    // Verify presence of required tokens
+    if (!laravelSession || !xsrfToken) {
+        ws.close(401, 'Unauthorized: Missing required tokens');
+        return;
+    }
+    const response = await axios.post(`http://coolify:8080/terminal/auth/ips`, null, {
+        headers: {
+            'Cookie': `${sessionCookieName}=${laravelSession}`,
+            'X-XSRF-TOKEN': xsrfToken
+        },
+    });
+    userSession.authorizedIPs = response.data.ipAddresses || [];
     userSessions.set(userId, userSession);
 
     ws.on('message', (message) => {
@@ -125,6 +144,20 @@ async function handleCommand(ws, command, userId) {
     const timeout = extractTimeout(commandString);
     const sshArgs = extractSshArgs(commandString);
     const hereDocContent = extractHereDocContent(commandString);
+
+    // Extract target host from SSH command
+    const targetHost = extractTargetHost(sshArgs);
+    if (!targetHost) {
+        ws.send('Invalid SSH command: No target host found');
+        return;
+    }
+
+    // Validate target host against authorized IPs
+    if (!userSession.authorizedIPs.includes(targetHost)) {
+        ws.send(`Unauthorized: Target host ${targetHost} not in authorized list`);
+        return;
+    }
+
     const options = {
         name: 'xterm-color',
         cols: 80,
@@ -152,7 +185,6 @@ async function handleCommand(ws, command, userId) {
         console.error(`Process exited with code ${exitCode} and signal ${signal}`);
         ws.send('pty-exited');
         userSession.isActive = false;
-
     });
 
     if (timeout) {
@@ -162,6 +194,22 @@ async function handleCommand(ws, command, userId) {
     }
 }
 
+function extractTargetHost(sshArgs) {
+    // Find the argument that matches the pattern user@host
+    const userAtHost = sshArgs.find(arg => {
+        // Skip paths that contain 'storage/app/ssh/keys/'
+        if (arg.includes('storage/app/ssh/keys/')) {
+            return false;
+        }
+        return /^[^@]+@[^@]+$/.test(arg);
+    });
+    if (!userAtHost) return null;
+
+    // Extract host from user@host
+    const host = userAtHost.split('@')[1];
+    return host;
+}
+
 async function handleError(err, userId) {
     console.error('WebSocket error:', err);
     await killPtyProcess(userId);
diff --git a/routes/web.php b/routes/web.php
index 3edfec910..3ddd77361 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -149,6 +149,17 @@ Route::middleware(['auth', 'verified'])->group(function () {
         return response()->json(['authenticated' => false], 401);
     })->name('terminal.auth');
 
+    Route::post('/terminal/auth/ips', function () {
+        if (auth()->check()) {
+            $team = auth()->user()->currentTeam();
+            $ipAddresses = $team->servers()->pluck('ip')->toArray();
+
+            return response()->json(['ipAddresses' => $ipAddresses], 200);
+        }
+
+        return response()->json(['ipAddresses' => []], 401);
+    })->name('terminal.auth.ips');
+
     Route::prefix('invitations')->group(function () {
         Route::get('/{uuid}', [Controller::class, 'acceptInvitation'])->name('team.invitation.accept');
         Route::get('/{uuid}/revoke', [Controller::class, 'revoke_invitation'])->name('team.invitation.revoke');
From 41df085746f79564ac96b6ce4c569c80f33b0bcd Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Fri, 25 Apr 2025 15:35:42 +0200
Subject: [PATCH 004/282] chore(versions): update realtime version to 1.0.8 in
 versions.json
---
 other/nightly/versions.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index 31e0e279d..6dc9e7a02 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -10,7 +10,7 @@
             "version": "1.0.8"
         },
         "realtime": {
-            "version": "1.0.7"
+            "version": "1.0.8"
         },
         "sentinel": {
             "version": "0.0.15"
From 0b26ea423cb71bfff904dcc192a5bed812eb755c Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Mon, 28 Apr 2025 10:44:17 +0200
Subject: [PATCH 005/282] chore(versions): update realtime version to 1.0.8 in
 versions.json
---
 versions.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/versions.json b/versions.json
index 31e0e279d..6dc9e7a02 100644
--- a/versions.json
+++ b/versions.json
@@ -10,7 +10,7 @@
             "version": "1.0.8"
         },
         "realtime": {
-            "version": "1.0.7"
+            "version": "1.0.8"
         },
         "sentinel": {
             "version": "0.0.15"
From f4472909ede6589f869a49fbb865d76dc330f5ee Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Mon, 28 Apr 2025 10:55:31 +0200
Subject: [PATCH 006/282] chore(docker): update soketi image version to 1.0.8
 in production configuration files
---
 docker-compose.prod.yml               | 2 +-
 other/nightly/docker-compose.prod.yml | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml
index 35fea6403..965fca276 100644
--- a/docker-compose.prod.yml
+++ b/docker-compose.prod.yml
@@ -61,7 +61,7 @@ services:
       retries: 10
       timeout: 2s
   soketi:
-    image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.6'
+    image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.8'
     ports:
       - "${SOKETI_PORT:-6001}:6001"
       - "6002:6002"
diff --git a/other/nightly/docker-compose.prod.yml b/other/nightly/docker-compose.prod.yml
index 35fea6403..fa30677ad 100644
--- a/other/nightly/docker-compose.prod.yml
+++ b/other/nightly/docker-compose.prod.yml
@@ -61,7 +61,7 @@ services:
       retries: 10
       timeout: 2s
   soketi:
-    image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.6'
+      image: '${REGISTRY_URL:-ghcr.io}/coollabsio/coolify-realtime:1.0.8'
     ports:
       - "${SOKETI_PORT:-6001}:6001"
       - "6002:6002"
From 8efcaf642af27edf22aad0524df385a7665d2118 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Mon, 28 Apr 2025 10:55:34 +0200
Subject: [PATCH 007/282] chore(versions): update coolify version to
 4.0.0-beta.414 and nightly version to 4.0.0-beta.415 in configuration files
---
 config/constants.php        | 2 +-
 other/nightly/versions.json | 4 ++--
 versions.json               | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/config/constants.php b/config/constants.php
index a849ae93e..018971370 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -2,7 +2,7 @@
 
 return [
     'coolify' => [
-        'version' => '4.0.0-beta.413',
+        'version' => '4.0.0-beta.414',
         'helper_version' => '1.0.8',
         'realtime_version' => '1.0.8',
         'self_hosted' => env('SELF_HOSTED', true),
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index 6dc9e7a02..aabcec3d8 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -1,10 +1,10 @@
 {
     "coolify": {
         "v4": {
-            "version": "4.0.0-beta.413"
+            "version": "4.0.0-beta.414"
         },
         "nightly": {
-            "version": "4.0.0-beta.414"
+            "version": "4.0.0-beta.415"
         },
         "helper": {
             "version": "1.0.8"
diff --git a/versions.json b/versions.json
index 6dc9e7a02..aabcec3d8 100644
--- a/versions.json
+++ b/versions.json
@@ -1,10 +1,10 @@
 {
     "coolify": {
         "v4": {
-            "version": "4.0.0-beta.413"
+            "version": "4.0.0-beta.414"
         },
         "nightly": {
-            "version": "4.0.0-beta.414"
+            "version": "4.0.0-beta.415"
         },
         "helper": {
             "version": "1.0.8"
From 75200717ddedced73320874dea25db0f32384e69 Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Mon, 28 Apr 2025 20:43:00 +0200
Subject: [PATCH 008/282] fix(ApplicationDeploymentJob): ensure source is an
 object before checking GitHub app properties
---
 app/Jobs/ApplicationDeploymentJob.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index c29093ce0..7c34271a7 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -1377,7 +1377,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
 
     private function check_git_if_build_needed()
     {
-        if ($this->source->getMorphClass() === \App\Models\GithubApp::class && $this->source->is_public === false) {
+        if (is_object($this->source) && $this->source->getMorphClass() === \App\Models\GithubApp::class && $this->source->is_public === false) {
             $repository = githubApi($this->source, "repos/{$this->customRepository}");
             $data = data_get($repository, 'data');
             if (isset($data->id)) {
From d47946a0ad00cc6344256fb053307c9209a6702a Mon Sep 17 00:00:00 2001
From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com>
Date: Tue, 29 Apr 2025 09:04:24 +0200
Subject: [PATCH 009/282] fix(ui): Disable livewire navigate feature (causing
 spam of setInterval())
---
 app/Livewire/Dashboard.php                    |  2 +-
 app/Livewire/Project/Application/Heading.php  |  4 +-
 app/Livewire/Project/Index.php                |  2 +-
 config/constants.php                          |  2 +-
 other/nightly/versions.json                   |  4 +-
 resources/views/components/navbar.blade.php   | 32 +++----
 .../components/notification/navbar.blade.php  |  7 +-
 .../resources/breadcrumbs.blade.php           |  2 -
 .../components/security/navbar.blade.php      |  4 +-
 .../views/components/server/navbar.blade.php  |  6 +-
 .../components/server/sidebar-proxy.blade.php |  6 +-
 .../views/components/server/sidebar.blade.php | 16 ++--
 .../components/settings/navbar.blade.php      |  6 +-
 .../views/components/team/navbar.blade.php    |  7 +-
 resources/views/livewire/dashboard.blade.php  | 26 +++--
 .../livewire/destination/index.blade.php      |  4 +-
 .../application/configuration.blade.php       | 57 +++++------
 .../application/deployment/index.blade.php    | 95 +++++++++++--------
 .../project/application/heading.blade.php     |  8 +-
 .../project/database/configuration.blade.php  | 32 +++----
 .../project/database/heading.blade.php        |  7 +-
 .../database/scheduled-backups.blade.php      |  3 +-
 .../project/environment-edit.blade.php        |  4 +-
 .../views/livewire/project/index.blade.php    |  9 +-
 .../livewire/project/resource/index.blade.php | 43 +++------
 .../project/service/configuration.blade.php   | 42 ++++----
 .../livewire/project/service/index.blade.php  |  7 +-
 .../livewire/project/service/navbar.blade.php |  6 +-
 .../livewire/project/shared/metrics.blade.php |  2 +-
 .../shared/scheduled-task/all.blade.php       |  4 +-
 .../views/livewire/project/show.blade.php     |  2 -
 .../security/private-key/index.blade.php      | 23 ++---
 .../views/livewire/server/index.blade.php     |  2 +-
 .../environment/index.blade.php               |  6 +-
 .../livewire/shared-variables/index.blade.php |  6 +-
 .../shared-variables/project/index.blade.php  |  1 -
 .../livewire/source/github/change.blade.php   |  2 +-
 .../views/livewire/storage/index.blade.php    |  2 +-
 .../views/livewire/tags/deployments.blade.php |  2 +-
 resources/views/livewire/tags/show.blade.php  |  8 +-
 resources/views/source/all.blade.php          |  4 +-
 versions.json                                 |  4 +-
 42 files changed, 235 insertions(+), 276 deletions(-)
diff --git a/app/Livewire/Dashboard.php b/app/Livewire/Dashboard.php
index d89f2b970..edbdd25fe 100644
--- a/app/Livewire/Dashboard.php
+++ b/app/Livewire/Dashboard.php
@@ -51,7 +51,7 @@ class Dashboard extends Component
 
     public function navigateToProject($projectUuid)
     {
-        return $this->redirect(collect($this->projects)->firstWhere('uuid', $projectUuid)->navigateTo(), true);
+        return $this->redirect(collect($this->projects)->firstWhere('uuid', $projectUuid)->navigateTo(), navigate: false);
     }
 
     public function render()
diff --git a/app/Livewire/Project/Application/Heading.php b/app/Livewire/Project/Application/Heading.php
index 475d2dfa8..5b0ae12ef 100644
--- a/app/Livewire/Project/Application/Heading.php
+++ b/app/Livewire/Project/Application/Heading.php
@@ -100,7 +100,7 @@ class Heading extends Component
             'application_uuid' => $this->parameters['application_uuid'],
             'deployment_uuid' => $this->deploymentUuid,
             'environment_uuid' => $this->parameters['environment_uuid'],
-        ], navigate: true);
+        ], navigate: false);
     }
 
     protected function setDeploymentUuid()
@@ -147,7 +147,7 @@ class Heading extends Component
             'application_uuid' => $this->parameters['application_uuid'],
             'deployment_uuid' => $this->deploymentUuid,
             'environment_uuid' => $this->parameters['environment_uuid'],
-        ], navigate: true);
+        ], navigate: false);
     }
 
     public function render()
diff --git a/app/Livewire/Project/Index.php b/app/Livewire/Project/Index.php
index 8bf511a66..5347d74f0 100644
--- a/app/Livewire/Project/Index.php
+++ b/app/Livewire/Project/Index.php
@@ -35,6 +35,6 @@ class Index extends Component
     {
         $project = collect($this->projects)->firstWhere('uuid', $projectUuid);
 
-        return $this->redirect($project->navigateTo(), true);
+        return $this->redirect($project->navigateTo(), navigate: false);
     }
 }
diff --git a/config/constants.php b/config/constants.php
index 018971370..1479ae201 100644
--- a/config/constants.php
+++ b/config/constants.php
@@ -2,7 +2,7 @@
 
 return [
     'coolify' => [
-        'version' => '4.0.0-beta.414',
+        'version' => '4.0.0-beta.415',
         'helper_version' => '1.0.8',
         'realtime_version' => '1.0.8',
         'self_hosted' => env('SELF_HOSTED', true),
diff --git a/other/nightly/versions.json b/other/nightly/versions.json
index aabcec3d8..fc4d28de4 100644
--- a/other/nightly/versions.json
+++ b/other/nightly/versions.json
@@ -1,10 +1,10 @@
 {
     "coolify": {
         "v4": {
-            "version": "4.0.0-beta.414"
+            "version": "4.0.0-beta.415"
         },
         "nightly": {
-            "version": "4.0.0-beta.415"
+            "version": "4.0.0-beta.416"
         },
         "helper": {
             "version": "1.0.8"
diff --git a/resources/views/components/navbar.blade.php b/resources/views/components/navbar.blade.php
index 4148a61d3..9a75200b1 100644
--- a/resources/views/components/navbar.blade.php
+++ b/resources/views/components/navbar.blade.php
@@ -123,7 +123,7 @@