diff --git a/apps/api/package.json b/apps/api/package.json index c088cb521..419ddc65e 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -35,7 +35,6 @@ "fastify": "4.4.0", "fastify-plugin": "4.1.0", "generate-password": "1.7.0", - "get-port": "6.1.2", "got": "12.3.1", "is-ip": "5.0.0", "is-port-reachable": "4.0.0", diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 2985728a8..866053cc4 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -17,7 +17,7 @@ import { checkContainer, removeContainer } from './docker'; import { day } from './dayjs'; import * as serviceFields from './serviceFields' -export const version = '3.7.0'; +export const version = '3.7.1'; export const isDev = process.env.NODE_ENV === 'development'; const algorithm = 'aes-256-ctr'; @@ -545,21 +545,38 @@ export const supportedDatabaseTypesAndVersions = [ } ]; -export async function getFreeSSHLocalPort(id: string): Promise { - const { default: getPort, portNumbers } = await import('get-port'); +export async function getFreeSSHLocalPort(id: string): Promise { + const { default: isReachable } = await import('is-port-reachable'); const { remoteIpAddress, sshLocalPort } = await prisma.destinationDocker.findUnique({ where: { id } }) if (sshLocalPort) { return Number(sshLocalPort) } + + const data = await prisma.setting.findFirst(); + const { minPort, maxPort } = data; + const ports = await prisma.destinationDocker.findMany({ where: { sshLocalPort: { not: null }, remoteIpAddress: { not: remoteIpAddress } } }) - const alreadyConfigured = await prisma.destinationDocker.findFirst({ where: { remoteIpAddress, id: { not: id }, sshLocalPort: { not: null } } }) + + const alreadyConfigured = await prisma.destinationDocker.findFirst({ + where: { + remoteIpAddress, id: { not: id }, sshLocalPort: { not: null } + } + }) if (alreadyConfigured?.sshLocalPort) { await prisma.destinationDocker.update({ where: { id }, data: { sshLocalPort: alreadyConfigured.sshLocalPort } }) return Number(alreadyConfigured.sshLocalPort) } - const availablePort = await getPort({ port: portNumbers(10000, 10100), exclude: ports.map(p => p.sshLocalPort) }) - await prisma.destinationDocker.update({ where: { id }, data: { sshLocalPort: Number(availablePort) } }) - return Number(availablePort) + const range = generateRangeArray(minPort, maxPort) + console.log({ ports }) + const availablePorts = range.filter(port => !ports.map(p => p.sshLocalPort).includes(port)) + for (const port of availablePorts) { + const found = await isReachable(port, { host: 'localhost' }) + if (!found) { + await prisma.destinationDocker.update({ where: { id }, data: { sshLocalPort: Number(port) } }) + return Number(port) + } + } + return false } export async function createRemoteEngineConfiguration(id: string) { @@ -1208,7 +1225,7 @@ export async function checkExposedPort({ id, configuredPort, exposePort, dockerI } } export async function getFreeExposedPort(id, exposePort, dockerId, remoteIpAddress) { - const { default: getPort } = await import('get-port'); + const { default: checkPort } = await import('is-port-reachable'); const applicationUsed = await ( await prisma.application.findMany({ where: { exposePort: { not: null }, id: { not: id }, destinationDockerId: dockerId }, @@ -1222,22 +1239,23 @@ export async function getFreeExposedPort(id, exposePort, dockerId, remoteIpAddre }) ).map((a) => a.exposePort); const usedPorts = [...applicationUsed, ...serviceUsed]; - if (remoteIpAddress) { - const { default: checkPort } = await import('is-port-reachable'); - const found = await checkPort(exposePort, { host: remoteIpAddress }); - if (!found) { - return exposePort - } + if (usedPorts.includes(exposePort)) { return false } - return await getPort({ port: Number(exposePort), exclude: usedPorts }); + const found = await checkPort(exposePort, { host: remoteIpAddress || 'localhost' }); + if (!found) { + return exposePort + } + return false } +export function generateRangeArray(start, end) { + return Array.from({ length: (end - start) }, (v, k) => k + start); +} export async function getFreePublicPort(id, dockerId) { - const { default: getPort, portNumbers } = await import('get-port'); + const { default: isReachable } = await import('is-port-reachable'); const data = await prisma.setting.findFirst(); const { minPort, maxPort } = data; - const dbUsed = await ( await prisma.database.findMany({ where: { publicPort: { not: null }, id: { not: id }, destinationDockerId: dockerId }, @@ -1263,7 +1281,15 @@ export async function getFreePublicPort(id, dockerId) { }) ).map((a) => a.publicPort); const usedPorts = [...dbUsed, ...wpFtpUsed, ...wpUsed, ...minioUsed]; - return await getPort({ port: portNumbers(minPort, maxPort), exclude: usedPorts }); + const range = generateRangeArray(minPort, maxPort) + const availablePorts = range.filter(port => !usedPorts.includes(port)) + for (const port of availablePorts) { + const found = await isReachable(port, { host: 'localhost' }) + if (!found) { + return port + } + } + return false } export async function startTraefikTCPProxy( @@ -1645,7 +1671,7 @@ export async function configureServiceType({ } } }); - } else { + } else { await prisma.service.update({ where: { id }, data: { diff --git a/apps/api/src/routes/api/v1/databases/handlers.ts b/apps/api/src/routes/api/v1/databases/handlers.ts index 96c740440..77d27ebc1 100644 --- a/apps/api/src/routes/api/v1/databases/handlers.ts +++ b/apps/api/src/routes/api/v1/databases/handlers.ts @@ -433,9 +433,13 @@ export async function saveDatabaseSettings(request: FastifyRequest=6'} - dev: true /escape-html/1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -3277,7 +3271,6 @@ packages: /fraction.js/4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} - dev: true /fresh/0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} @@ -4321,7 +4314,6 @@ packages: /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} - dev: true /nodemon/2.0.19: resolution: {integrity: sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==} @@ -4367,7 +4359,6 @@ packages: /normalize-range/0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - dev: true /normalize-url/6.1.0: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} @@ -4830,7 +4821,6 @@ packages: requiresBuild: true dependencies: '@prisma/engines': 3.15.1-1.461d6a05159055555eb7dfb337c9fb271cbd4d7e - dev: true /private/0.1.8: resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} @@ -5616,7 +5606,6 @@ packages: /svelte/3.49.0: resolution: {integrity: sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==} engines: {node: '>= 8'} - dev: true /sveltekit-i18n/2.2.2_svelte@3.49.0: resolution: {integrity: sha512-6eygICleGCSL7elY7A3trF8XUhV+mlW56ZSoD0UUKXlw+Y6u0MTTHDq48u1LyY73SfnlbPHXgTarhTjZ0BvUKA==} @@ -5850,7 +5839,6 @@ packages: resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} engines: {node: '>=4.2.0'} hasBin: true - dev: true /typpy/2.3.11: resolution: {integrity: sha512-Jh/fykZSaxeKO0ceMAs6agki9T5TNA9kiIR6fzKbvafKpIw8UlNlHhzuqKyi5lfJJ5VojJOx9tooIbyy7vHV/g==} @@ -5885,7 +5873,6 @@ packages: browserslist: 4.21.3 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}