From df01139c415ad57a8f735e240df2d7293652f028 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Fri, 22 Jul 2022 08:57:11 +0000 Subject: [PATCH] fix: expose port checker --- apps/api/src/lib/common.ts | 20 +++++++++++-- .../routes/api/v1/applications/handlers.ts | 29 ++++++++++--------- .../src/routes/api/v1/databases/handlers.ts | 4 +-- .../src/routes/api/v1/services/handlers.ts | 27 ++++++++--------- 4 files changed, 47 insertions(+), 33 deletions(-) diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 9907895f0..e489fc52b 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -994,8 +994,24 @@ export async function updatePasswordInDb(database, user, newPassword, isRoot) { } } } - -export async function getFreePort() { +export async function getExposedFreePort(id, exposePort) { + const { default: getPort } = await import('get-port'); + const applicationUsed = await ( + await prisma.application.findMany({ + where: { exposePort: { not: null }, id: { not: id } }, + select: { exposePort: true } + }) + ).map((a) => a.exposePort); + const serviceUsed = await ( + await prisma.service.findMany({ + where: { exposePort: { not: null }, id: { not: id } }, + select: { exposePort: true } + }) + ).map((a) => a.exposePort); + const usedPorts = [...applicationUsed, ...serviceUsed]; + return await getPort({ port: exposePort, exclude: usedPorts }); +} +export async function getFreePublicPort() { const { default: getPort, portNumbers } = await import('get-port'); const data = await prisma.setting.findFirst(); const { minPort, maxPort } = data; diff --git a/apps/api/src/routes/api/v1/applications/handlers.ts b/apps/api/src/routes/api/v1/applications/handlers.ts index 0eca0249c..bfa0067a9 100644 --- a/apps/api/src/routes/api/v1/applications/handlers.ts +++ b/apps/api/src/routes/api/v1/applications/handlers.ts @@ -5,7 +5,7 @@ import axios from 'axios'; import { FastifyReply } from 'fastify'; import { day } from '../../../../lib/dayjs'; import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; -import { asyncExecShell, checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common'; +import { checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, executeDockerCmd, generateSshKeyPair, getContainerUsage, getDomain, getExposedFreePort, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common'; import { checkContainer, dockerInstance, isContainerExited, removeContainer } from '../../../../lib/docker'; import { scheduler } from '../../../../lib/scheduler'; @@ -57,7 +57,7 @@ export async function getImages(request: FastifyRequest) { } - return { baseImage, baseBuildImage, baseBuildImages, baseImages, publishDirectory, port } + return { baseBuildImage, baseBuildImages, publishDirectory, port } } catch ({ status, message }) { return errorHandler({ status, message }) } @@ -249,6 +249,7 @@ export async function saveApplication(request: FastifyRequest, dockerFileLocation, denoMainFile }); + console.log({ baseImage }) await prisma.application.update({ where: { id }, data: { @@ -352,7 +353,9 @@ export async function checkDNS(request: FastifyRequest) { const { id } = request.params let { exposePort, fqdn, forceSave, dualCerts } = request.body - fqdn = fqdn.toLowerCase(); + + if (fqdn) fqdn = fqdn.toLowerCase(); + if (exposePort) exposePort = Number(exposePort); const { isDNSCheckEnabled } = await prisma.setting.findFirst({}); const found = await isDomainConfigured({ id, fqdn }); @@ -360,14 +363,12 @@ export async function checkDNS(request: FastifyRequest) { throw { status: 500, message: `Domain ${getDomain(fqdn).replace('www.', '')} is already in use!` } } if (exposePort) { - exposePort = Number(exposePort); if (exposePort < 1024 || exposePort > 65535) { throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` } } - const { default: getPort } = await import('get-port'); - const publicPort = await getPort({ port: exposePort }); - if (publicPort !== exposePort) { + const availablePort = await getExposedFreePort(id, exposePort); + if (availablePort.toString() !== exposePort.toString()) { throw { status: 500, message: `Port ${exposePort} is already in use.` } } } @@ -765,13 +766,13 @@ export async function getApplicationLogs(request: FastifyRequest ansi(l)).filter((a) => a); - const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); - const logs = stripLogsStderr.concat(stripLogsStdout) - const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) - return { logs: sortedLogs } + const { default: ansi } = await import('strip-ansi') + const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) + const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); + const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); + const logs = stripLogsStderr.concat(stripLogsStdout) + const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) + return { logs: sortedLogs } // } } catch (error) { const { statusCode } = error; diff --git a/apps/api/src/routes/api/v1/databases/handlers.ts b/apps/api/src/routes/api/v1/databases/handlers.ts index 670de896d..7ce0eb557 100644 --- a/apps/api/src/routes/api/v1/databases/handlers.ts +++ b/apps/api/src/routes/api/v1/databases/handlers.ts @@ -3,7 +3,7 @@ import type { FastifyRequest } from 'fastify'; import { FastifyReply } from 'fastify'; import yaml from 'js-yaml'; import fs from 'fs/promises'; -import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; +import { ComposeFile, createDirectories, decrypt, encrypt, errorHandler, executeDockerCmd, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePublicPort, listSettings, makeLabelForStandaloneDatabase, prisma, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { checkContainer } from '../../../../lib/docker'; import { day } from '../../../../lib/dayjs'; @@ -431,7 +431,7 @@ export async function saveDatabaseSettings(request: FastifyRequest) { try { // const found = await checkContainer({ dockerId, container: id }) // if (found) { - const { default: ansi } = await import('strip-ansi') - const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) - const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); - const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); - const logs = stripLogsStderr.concat(stripLogsStdout) - const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) - return { logs: sortedLogs } + const { default: ansi } = await import('strip-ansi') + const { stdout, stderr } = await executeDockerCmd({ dockerId, command: `docker logs --since ${since} --tail 5000 --timestamps ${id}` }) + const stripLogsStdout = stdout.toString().split('\n').map((l) => ansi(l)).filter((a) => a); + const stripLogsStderr = stderr.toString().split('\n').map((l) => ansi(l)).filter((a) => a); + const logs = stripLogsStderr.concat(stripLogsStdout) + const sortedLogs = logs.sort((a, b) => (day(a.split(' ')[0]).isAfter(day(b.split(' ')[0])) ? 1 : -1)) + return { logs: sortedLogs } // } } catch (error) { const { statusCode } = error; @@ -373,15 +373,12 @@ export async function checkService(request: FastifyRequest) { } } if (exposePort) { - const { default: getPort } = await import('get-port'); - exposePort = Number(exposePort); - if (exposePort < 1024 || exposePort > 65535) { throw { status: 500, message: `Exposed Port needs to be between 1024 and 65535.` } } - const publicPort = await getPort({ port: exposePort }); - if (publicPort !== exposePort) { + const availablePort = await getExposedFreePort(id, exposePort); + if (availablePort.toString() !== exposePort.toString()) { throw { status: 500, message: `Port ${exposePort} is already in use.` } } } @@ -983,7 +980,7 @@ async function startMinioService(request: FastifyRequest) { const network = destinationDockerId && destinationDocker.network; const port = getServiceMainPort('minio'); - const publicPort = await getFreePort(); + const publicPort = await getFreePublicPort(); const consolePort = 9001; const { workdir } = await createDirectories({ repository: type, buildId: id }); @@ -2679,7 +2676,7 @@ export async function activateWordpressFtp(request: FastifyRequest