diff --git a/apps/api/package.json b/apps/api/package.json index 86f78ab39..32b303b4f 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -26,8 +26,6 @@ "@iarna/toml": "2.2.5", "@ladjs/graceful": "3.2.1", "@prisma/client": "4.8.1", - "@sentry/node": "7.30.0", - "@sentry/tracing": "7.30.0", "axe": "11.2.1", "bcryptjs": "2.4.3", "bree": "9.1.3", diff --git a/apps/api/prisma/seed.js b/apps/api/prisma/seed.js index 2364e3b3c..e335607ac 100644 --- a/apps/api/prisma/seed.js +++ b/apps/api/prisma/seed.js @@ -102,14 +102,17 @@ async function reEncryptSecrets() { } if (secretOld !== secretNew) { console.log('secrets are different, so re-encrypting'); - // const secrets = await prisma.secret.findMany(); - // if (secrets.length > 0) { - // for (const secret of secrets) { - // const value = decrypt(secret.value, secretOld); - // const newValue = encrypt(value, secretNew); - // console.log({ value: secret.value, newValue }); - // } - // } + const secrets = await prisma.secret.findMany(); + if (secrets.length > 0) { + for (const secret of secrets) { + const value = decrypt(secret.value, secretOld); + const newValue = encrypt(value, secretNew); + await prisma.secret.update({ + where: { id: secret.id }, + data: { value: newValue } + }); + } + } } } main() diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 2281f53d1..2d57842e9 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -18,7 +18,6 @@ import { isDev, listSettings, prisma, - sentryDSN, startTraefikProxy, startTraefikTCPProxy, version @@ -32,7 +31,6 @@ import { verifyRemoteDockerEngineFn } from './routes/api/v1/destinations/handler import { checkContainer } from './lib/docker'; import { migrateApplicationPersistentStorage, migrateServicesToNewTemplate } from './lib'; import { refreshTags, refreshTemplates } from './routes/api/v1/handlers'; -import * as Sentry from '@sentry/node'; declare module 'fastify' { interface FastifyInstance { config: { @@ -281,9 +279,6 @@ async function initServer() { if (settings.doNotTrack === true) { console.log('[000] Telemetry disabled...'); } else { - if (settings.sentryDSN !== sentryDSN) { - await prisma.setting.update({ where: { id: '0' }, data: { sentryDSN } }); - } // Initialize Sentry // Sentry.init({ // dsn: sentryDSN, diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index a00031ab3..8bf2891c1 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -8,7 +8,6 @@ import type { Config } from 'unique-names-generator'; import generator from 'generate-password'; import crypto from 'crypto'; import { promises as dns } from 'dns'; -import * as Sentry from '@sentry/node'; import { PrismaClient } from '@prisma/client'; import os from 'os'; import * as SSHConfig from 'ssh-config/src/ssh-config'; @@ -23,8 +22,7 @@ export const version = '3.12.33'; export const isDev = process.env.NODE_ENV === 'development'; export const proxyPort = process.env.COOLIFY_PROXY_PORT; export const proxySecurePort = process.env.COOLIFY_PROXY_SECURE_PORT; -export const sentryDSN = - 'https://409f09bcb7af47928d3e0f46b78987f3@o1082494.ingest.sentry.io/4504236622217216'; + const algorithm = 'aes-256-ctr'; const customConfig: Config = { dictionaries: [adjectives, colors, animals], @@ -1685,9 +1683,6 @@ export function errorHandler({ if (message.includes('Unique constraint failed')) { message = 'This data is unique and already exists. Please try again with a different value.'; } - if (type === 'normal') { - Sentry.captureException(message); - } throw { status, message }; } export async function generateSshKeyPair(): Promise<{ publicKey: string; privateKey: string }> { diff --git a/apps/api/src/plugins/jwt.ts b/apps/api/src/plugins/jwt.ts index 62083be1a..1a50fca4f 100644 --- a/apps/api/src/plugins/jwt.ts +++ b/apps/api/src/plugins/jwt.ts @@ -13,8 +13,12 @@ declare module '@fastify/jwt' { } export default fp(async (fastify, opts) => { + let secretKey = fastify.config.COOLIFY_SECRET_KEY_BETTER; + if (!secretKey) { + secretKey = fastify.config.COOLIFY_SECRET_KEY; + } fastify.register(fastifyJwt, { - secret: fastify.config.COOLIFY_SECRET_KEY_BETTER ?? fastify.config.COOLIFY_SECRET_KEY + secret: secretKey }); fastify.decorate('authenticate', async function (request, reply) { diff --git a/apps/api/src/routes/api/v1/handlers.ts b/apps/api/src/routes/api/v1/handlers.ts index 5cb283137..69c73b940 100644 --- a/apps/api/src/routes/api/v1/handlers.ts +++ b/apps/api/src/routes/api/v1/handlers.ts @@ -12,7 +12,6 @@ import { prisma, uniqueName, version, - sentryDSN, executeCommand } from '../../../lib/common'; import { scheduler } from '../../../lib/scheduler'; @@ -452,7 +451,6 @@ export async function getCurrentUser(request: FastifyRequest, fa }); return { settings: await prisma.setting.findUnique({ where: { id: '0' } }), - sentryDSN, pendingInvitations, token, ...request.user diff --git a/apps/api/src/routes/api/v1/settings/handlers.ts b/apps/api/src/routes/api/v1/settings/handlers.ts index 1f0ecb006..929bef1b8 100644 --- a/apps/api/src/routes/api/v1/settings/handlers.ts +++ b/apps/api/src/routes/api/v1/settings/handlers.ts @@ -1,235 +1,312 @@ import { promises as dns } from 'dns'; import { X509Certificate } from 'node:crypto'; -import * as Sentry from '@sentry/node'; import type { FastifyReply, FastifyRequest } from 'fastify'; -import { checkDomainsIsValidInDNS, decrypt, encrypt, errorHandler, executeCommand, getDomain, isDev, isDNSValid, isDomainConfigured, listSettings, prisma, sentryDSN, version } from '../../../../lib/common'; -import { AddDefaultRegistry, CheckDNS, CheckDomain, DeleteDomain, OnlyIdInBody, SaveSettings, SaveSSHKey, SetDefaultRegistry } from './types'; - +import { + checkDomainsIsValidInDNS, + decrypt, + encrypt, + errorHandler, + executeCommand, + getDomain, + isDev, + isDNSValid, + isDomainConfigured, + listSettings, + prisma +} from '../../../../lib/common'; +import { + AddDefaultRegistry, + CheckDNS, + CheckDomain, + DeleteDomain, + OnlyIdInBody, + SaveSettings, + SaveSSHKey, + SetDefaultRegistry +} from './types'; export async function listAllSettings(request: FastifyRequest) { - try { - const teamId = request.user.teamId; - const settings = await listSettings(); - const sshKeys = await prisma.sshKey.findMany({ where: { team: { id: teamId } } }) - let registries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId } } }) - registries = registries.map((registry) => { - if (registry.password) { - registry.password = decrypt(registry.password) - } - return registry - }) - const unencryptedKeys = [] - if (sshKeys.length > 0) { - for (const key of sshKeys) { - unencryptedKeys.push({ id: key.id, name: key.name, privateKey: decrypt(key.privateKey), createdAt: key.createdAt }) - } - } - const certificates = await prisma.certificate.findMany({ where: { team: { id: teamId } } }) - let cns = []; - for (const certificate of certificates) { - const x509 = new X509Certificate(certificate.cert); - cns.push({ commonName: x509.subject.split('\n').find((s) => s.startsWith('CN=')).replace('CN=', ''), id: certificate.id, createdAt: certificate.createdAt }) - } + try { + const teamId = request.user.teamId; + const settings = await listSettings(); + const sshKeys = await prisma.sshKey.findMany({ where: { team: { id: teamId } } }); + let registries = await prisma.dockerRegistry.findMany({ where: { team: { id: teamId } } }); + registries = registries.map((registry) => { + if (registry.password) { + registry.password = decrypt(registry.password); + } + return registry; + }); + const unencryptedKeys = []; + if (sshKeys.length > 0) { + for (const key of sshKeys) { + unencryptedKeys.push({ + id: key.id, + name: key.name, + privateKey: decrypt(key.privateKey), + createdAt: key.createdAt + }); + } + } + const certificates = await prisma.certificate.findMany({ where: { team: { id: teamId } } }); + let cns = []; + for (const certificate of certificates) { + const x509 = new X509Certificate(certificate.cert); + cns.push({ + commonName: x509.subject + .split('\n') + .find((s) => s.startsWith('CN=')) + .replace('CN=', ''), + id: certificate.id, + createdAt: certificate.createdAt + }); + } - return { - settings, - certificates: cns, - sshKeys: unencryptedKeys, - registries - } - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + return { + settings, + certificates: cns, + sshKeys: unencryptedKeys, + registries + }; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function saveSettings(request: FastifyRequest, reply: FastifyReply) { - try { - let { - previewSeparator, - numberOfDockerImagesKeptLocally, - doNotTrack, - fqdn, - isAPIDebuggingEnabled, - isRegistrationEnabled, - dualCerts, - minPort, - maxPort, - isAutoUpdateEnabled, - isDNSCheckEnabled, - DNSServers, - proxyDefaultRedirect - } = request.body - const { id, previewSeparator: SetPreviewSeparator } = await listSettings(); - if (numberOfDockerImagesKeptLocally) { - numberOfDockerImagesKeptLocally = Number(numberOfDockerImagesKeptLocally) - } - if (previewSeparator == '') { - previewSeparator = '.' - } - if (SetPreviewSeparator != previewSeparator) { - const applications = await prisma.application.findMany({ where: { previewApplication: { some: { id: { not: undefined } } } }, include: { previewApplication: true } }) - for (const application of applications) { - for (const preview of application.previewApplication) { - const { protocol } = new URL(preview.customDomain) - const { pullmergeRequestId } = preview - const { fqdn } = application - const newPreviewDomain = `${protocol}//${pullmergeRequestId}${previewSeparator}${getDomain(fqdn)}` - await prisma.previewApplication.update({ where: { id: preview.id }, data: { customDomain: newPreviewDomain } }) - } - } - } + try { + let { + previewSeparator, + numberOfDockerImagesKeptLocally, + doNotTrack, + fqdn, + isAPIDebuggingEnabled, + isRegistrationEnabled, + dualCerts, + minPort, + maxPort, + isAutoUpdateEnabled, + isDNSCheckEnabled, + DNSServers, + proxyDefaultRedirect + } = request.body; + const { id, previewSeparator: SetPreviewSeparator } = await listSettings(); + if (numberOfDockerImagesKeptLocally) { + numberOfDockerImagesKeptLocally = Number(numberOfDockerImagesKeptLocally); + } + if (previewSeparator == '') { + previewSeparator = '.'; + } + if (SetPreviewSeparator != previewSeparator) { + const applications = await prisma.application.findMany({ + where: { previewApplication: { some: { id: { not: undefined } } } }, + include: { previewApplication: true } + }); + for (const application of applications) { + for (const preview of application.previewApplication) { + const { protocol } = new URL(preview.customDomain); + const { pullmergeRequestId } = preview; + const { fqdn } = application; + const newPreviewDomain = `${protocol}//${pullmergeRequestId}${previewSeparator}${getDomain( + fqdn + )}`; + await prisma.previewApplication.update({ + where: { id: preview.id }, + data: { customDomain: newPreviewDomain } + }); + } + } + } - await prisma.setting.update({ - where: { id }, - data: { previewSeparator, numberOfDockerImagesKeptLocally, doNotTrack, isRegistrationEnabled, dualCerts, isAutoUpdateEnabled, isDNSCheckEnabled, DNSServers, isAPIDebuggingEnabled } - }); - if (fqdn) { - await prisma.setting.update({ where: { id }, data: { fqdn } }); - } - await prisma.setting.update({ where: { id }, data: { proxyDefaultRedirect } }); - if (minPort && maxPort) { - await prisma.setting.update({ where: { id }, data: { minPort, maxPort } }); - } - if (doNotTrack === false) { - // Sentry.init({ - // dsn: sentryDSN, - // environment: isDev ? 'development' : 'production', - // release: version - // }); - // console.log('Sentry initialized') - } - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + await prisma.setting.update({ + where: { id }, + data: { + previewSeparator, + numberOfDockerImagesKeptLocally, + doNotTrack, + isRegistrationEnabled, + dualCerts, + isAutoUpdateEnabled, + isDNSCheckEnabled, + DNSServers, + isAPIDebuggingEnabled + } + }); + if (fqdn) { + await prisma.setting.update({ where: { id }, data: { fqdn } }); + } + await prisma.setting.update({ where: { id }, data: { proxyDefaultRedirect } }); + if (minPort && maxPort) { + await prisma.setting.update({ where: { id }, data: { minPort, maxPort } }); + } + if (doNotTrack === false) { + // Sentry.init({ + // dsn: sentryDSN, + // environment: isDev ? 'development' : 'production', + // release: version + // }); + // console.log('Sentry initialized') + } + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function deleteDomain(request: FastifyRequest, reply: FastifyReply) { - try { - const { fqdn } = request.body - const { DNSServers } = await listSettings(); - if (DNSServers) { - dns.setServers([...DNSServers.split(',')]); - } - let ip; - try { - ip = await dns.resolve(fqdn); - } catch (error) { - // Do not care. - } - await prisma.setting.update({ where: { fqdn }, data: { fqdn: null } }); - return reply.redirect(302, ip ? `http://${ip[0]}:3000/settings` : undefined) - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + try { + const { fqdn } = request.body; + const { DNSServers } = await listSettings(); + if (DNSServers) { + dns.setServers([...DNSServers.split(',')]); + } + let ip; + try { + ip = await dns.resolve(fqdn); + } catch (error) { + // Do not care. + } + await prisma.setting.update({ where: { fqdn }, data: { fqdn: null } }); + return reply.redirect(302, ip ? `http://${ip[0]}:3000/settings` : undefined); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function checkDomain(request: FastifyRequest) { - try { - const { id } = request.params; - let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = request.body - if (fqdn) fqdn = fqdn.toLowerCase(); - const found = await isDomainConfigured({ id, fqdn }); - if (found) { - throw { message: "Domain already configured" }; - } - if (isDNSCheckEnabled && !forceSave && !isDev) { - const hostname = request.hostname.split(':')[0] - return await checkDomainsIsValidInDNS({ hostname, fqdn, dualCerts }); - } - return {}; - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + try { + const { id } = request.params; + let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = request.body; + if (fqdn) fqdn = fqdn.toLowerCase(); + const found = await isDomainConfigured({ id, fqdn }); + if (found) { + throw { message: 'Domain already configured' }; + } + if (isDNSCheckEnabled && !forceSave && !isDev) { + const hostname = request.hostname.split(':')[0]; + return await checkDomainsIsValidInDNS({ hostname, fqdn, dualCerts }); + } + return {}; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function checkDNS(request: FastifyRequest) { - try { - const { domain } = request.params; - await isDNSValid(request.hostname, domain); - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + try { + const { domain } = request.params; + await isDNSValid(request.hostname, domain); + return {}; + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function saveSSHKey(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { privateKey, name } = request.body; - const found = await prisma.sshKey.findMany({ where: { name } }) - if (found.length > 0) { - throw { - message: "Name already used. Choose another one please." - } - } - const encryptedSSHKey = encrypt(privateKey) - await prisma.sshKey.create({ data: { name, privateKey: encryptedSSHKey, team: { connect: { id: teamId } } } }) - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + try { + const teamId = request.user.teamId; + const { privateKey, name } = request.body; + const found = await prisma.sshKey.findMany({ where: { name } }); + if (found.length > 0) { + throw { + message: 'Name already used. Choose another one please.' + }; + } + const encryptedSSHKey = encrypt(privateKey); + await prisma.sshKey.create({ + data: { name, privateKey: encryptedSSHKey, team: { connect: { id: teamId } } } + }); + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } export async function deleteSSHKey(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { id } = request.body; - await prisma.sshKey.deleteMany({ where: { id, teamId } }) - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + try { + const teamId = request.user.teamId; + const { id } = request.body; + await prisma.sshKey.deleteMany({ where: { id, teamId } }); + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } -export async function deleteCertificates(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { id } = request.body; - await executeCommand({ command: `docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`, shell: true }) - await prisma.certificate.deleteMany({ where: { id, teamId } }) - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } +export async function deleteCertificates( + request: FastifyRequest, + reply: FastifyReply +) { + try { + const teamId = request.user.teamId; + const { id } = request.body; + await executeCommand({ + command: `docker exec coolify-proxy sh -c 'rm -f /etc/traefik/acme/custom/${id}-key.pem /etc/traefik/acme/custom/${id}-cert.pem'`, + shell: true + }); + await prisma.certificate.deleteMany({ where: { id, teamId } }); + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } -export async function setDockerRegistry(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { id, username, password } = request.body; +export async function setDockerRegistry( + request: FastifyRequest, + reply: FastifyReply +) { + try { + const teamId = request.user.teamId; + const { id, username, password } = request.body; - let encryptedPassword = '' - if (password) encryptedPassword = encrypt(password) + let encryptedPassword = ''; + if (password) encryptedPassword = encrypt(password); - if (teamId === '0') { - await prisma.dockerRegistry.update({ where: { id }, data: { username, password: encryptedPassword } }) - } else { - await prisma.dockerRegistry.updateMany({ where: { id, teamId }, data: { username, password: encryptedPassword } }) - } - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + if (teamId === '0') { + await prisma.dockerRegistry.update({ + where: { id }, + data: { username, password: encryptedPassword } + }); + } else { + await prisma.dockerRegistry.updateMany({ + where: { id, teamId }, + data: { username, password: encryptedPassword } + }); + } + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } -export async function addDockerRegistry(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { name, url, username, password } = request.body; +export async function addDockerRegistry( + request: FastifyRequest, + reply: FastifyReply +) { + try { + const teamId = request.user.teamId; + const { name, url, username, password } = request.body; - let encryptedPassword = '' - if (password) encryptedPassword = encrypt(password) - await prisma.dockerRegistry.create({ data: { name, url, username, password: encryptedPassword, team: { connect: { id: teamId } } } }) + let encryptedPassword = ''; + if (password) encryptedPassword = encrypt(password); + await prisma.dockerRegistry.create({ + data: { name, url, username, password: encryptedPassword, team: { connect: { id: teamId } } } + }); - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } +} +export async function deleteDockerRegistry( + request: FastifyRequest, + reply: FastifyReply +) { + try { + const teamId = request.user.teamId; + const { id } = request.body; + await prisma.application.updateMany({ + where: { dockerRegistryId: id }, + data: { dockerRegistryId: null } + }); + await prisma.dockerRegistry.deleteMany({ where: { id, teamId } }); + return reply.code(201).send(); + } catch ({ status, message }) { + return errorHandler({ status, message }); + } } -export async function deleteDockerRegistry(request: FastifyRequest, reply: FastifyReply) { - try { - const teamId = request.user.teamId; - const { id } = request.body; - await prisma.application.updateMany({ where: { dockerRegistryId: id }, data: { dockerRegistryId: null } }) - await prisma.dockerRegistry.deleteMany({ where: { id, teamId } }) - return reply.code(201).send() - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} \ No newline at end of file diff --git a/apps/ui/package.json b/apps/ui/package.json index d40dba2a0..1cadeffd8 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -42,8 +42,6 @@ }, "type": "module", "dependencies": { - "@sentry/svelte": "7.21.1", - "@sentry/tracing": "7.21.1", "@sveltejs/adapter-static": "1.0.0-next.48", "@tailwindcss/typography": "0.5.8", "cuid": "2.1.8", diff --git a/apps/ui/src/hooks.ts b/apps/ui/src/hooks.ts index df3284d5a..6723af14f 100644 --- a/apps/ui/src/hooks.ts +++ b/apps/ui/src/hooks.ts @@ -1,13 +1,10 @@ -import * as Sentry from '@sentry/svelte'; export async function handle({ event, resolve }) { - const response = await resolve(event, { ssr: false }); - return response; + const response = await resolve(event, { ssr: false }); + return response; } export const handleError = ({ error, event }) => { - Sentry.captureException(error, { event }); - - return { - message: 'Whoops!', - code: error?.code ?? 'UNKNOWN' - }; -}; \ No newline at end of file + return { + message: 'Whoops!', + code: error?.code ?? 'UNKNOWN' + }; +}; diff --git a/apps/ui/src/routes/__layout.svelte b/apps/ui/src/routes/__layout.svelte index 310cc3fac..1c432fd5a 100644 --- a/apps/ui/src/routes/__layout.svelte +++ b/apps/ui/src/routes/__layout.svelte @@ -65,7 +65,6 @@