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! Arvensis Systems Niklas Lausch Cap-go +InterviewPal + ...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 @@