refactor: update filesystem encryption handling and configuration

refactor: simplify server startup script and move provider/config checks to separate files

docs: update documentation to reflect encryption changes and default UID/GID values

- Changed default behavior to disable filesystem encryption for improved performance.
- Updated environment variable handling for DISABLE_FILESYSTEM_ENCRYPTION and ENCRYPTION_KEY across multiple configuration files.
- Added new scripts and configuration files for managing application settings and providers.
- Adjusted Dockerfile and server start scripts to reflect changes in UID/GID handling and file management.
- Enhanced documentation to clarify encryption options and their implications.
This commit is contained in:
Daniel Luiz Alves
2025-07-22 16:02:44 -03:00
parent d3e76c19bf
commit 32f0a891ba
19 changed files with 352 additions and 266 deletions

147
infra/check-missing.js Normal file
View File

@@ -0,0 +1,147 @@
const { PrismaClient } = require('@prisma/client');
const fs = require('fs');
const path = require('path');
const prisma = new PrismaClient();
const loadConfigs = () => {
try {
const configsPath = path.join(__dirname, 'configs.json');
const configs = JSON.parse(fs.readFileSync(configsPath, 'utf8'));
return Object.values(configs).flat();
} catch (error) {
console.error('Error loading configs:', error.message);
return [];
}
};
const loadProviders = () => {
try {
const providersPath = path.join(__dirname, 'providers.json');
return JSON.parse(fs.readFileSync(providersPath, 'utf8'));
} catch (error) {
console.error('Error loading providers:', error.message);
return [];
}
};
async function checkSeedingNeeded() {
try {
const appConfigCount = await prisma.appConfig.count();
const userCount = await prisma.user.count();
const authProviderCount = await prisma.authProvider.count();
if (appConfigCount === 0 || userCount === 0) {
console.log('true');
return;
}
if (authProviderCount === 0) {
console.log('true');
return;
}
const allConfigs = loadConfigs();
const existingConfigs = await prisma.appConfig.findMany({
where: {
key: {
in: allConfigs
}
},
select: { key: true }
});
const existingConfigKeys = existingConfigs.map(c => c.key);
const missingConfigs = allConfigs.filter(key => !existingConfigKeys.includes(key));
if (missingConfigs.length > 0) {
console.log('true');
return;
}
const expectedProviders = loadProviders();
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('true');
return;
}
console.log('false');
} catch (error) {
console.error('Error checking if seeding is needed:', error);
console.log('true');
} finally {
await prisma.$disconnect();
}
}
async function checkMissingProviders() {
try {
const expectedProviders = loadProviders();
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('Missing providers: ' + missingProviders.join(', '));
} else {
console.log('No missing providers');
}
} catch (error) {
console.error('Error checking missing providers:', error);
console.log('Error checking providers');
} finally {
await prisma.$disconnect();
}
}
async function checkMissingConfigs() {
try {
const allConfigs = loadConfigs();
const existingConfigs = await prisma.appConfig.findMany({
where: {
key: {
in: allConfigs
}
},
select: { key: true }
});
const existingConfigKeys = existingConfigs.map(c => c.key);
const missingConfigs = allConfigs.filter(key => !existingConfigKeys.includes(key));
if (missingConfigs.length > 0) {
console.log('Missing configurations: ' + missingConfigs.join(', '));
} else {
console.log('No missing configurations');
}
} catch (error) {
console.error('Error checking missing configurations:', error);
console.log('Error checking configurations');
} finally {
await prisma.$disconnect();
}
}
const command = process.argv[2];
switch (command) {
case 'check-seeding':
checkSeedingNeeded();
break;
case 'check-providers':
checkMissingProviders();
break;
case 'check-configs':
checkMissingConfigs();
break;
default:
console.error('Unknown command. Use: check-seeding, check-providers, or check-configs');
process.exit(1);
}

37
infra/configs.json Normal file
View File

@@ -0,0 +1,37 @@
{
"general": [
"appName",
"showHomePage",
"appDescription",
"appLogo",
"firstUserAccess",
"serverUrl"
],
"storage": [
"maxFileSize",
"maxTotalStoragePerUser"
],
"security": [
"jwtSecret",
"maxLoginAttempts",
"loginBlockDuration",
"passwordMinLength",
"passwordAuthEnabled",
"passwordResetTokenExpiration"
],
"email": [
"smtpEnabled",
"smtpHost",
"smtpPort",
"smtpUser",
"smtpPass",
"smtpFromName",
"smtpFromEmail",
"smtpSecure",
"smtpNoAuth",
"smtpTrustSelfSigned"
],
"auth-providers": [
"authProvidersEnabled"
]
}

11
infra/providers.json Normal file
View File

@@ -0,0 +1,11 @@
[
"google",
"discord",
"github",
"auth0",
"kinde",
"zitadel",
"authentik",
"frontegg",
"pocketid"
]

View File

@@ -3,8 +3,8 @@ set -e
echo "🌴 Starting Palmr Server..."
TARGET_UID=${PALMR_UID:-1001}
TARGET_GID=${PALMR_GID:-1001}
TARGET_UID=${PALMR_UID:-1000}
TARGET_GID=${PALMR_GID:-1000}
if [ -n "$PALMR_UID" ] || [ -n "$PALMR_GID" ]; then
echo "🔧 Runtime UID/GID: $TARGET_UID:$TARGET_GID"
@@ -35,200 +35,59 @@ if [ "$(id -u)" = "0" ]; then
chown -R $TARGET_UID:$TARGET_GID /app/server/prisma 2>/dev/null || true
fi
run_as_user() {
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID "$@"
else
"$@"
fi
}
if [ ! -f "/app/server/prisma/configs.json" ]; then
echo "📄 Copying configuration files..."
cp -f /app/infra/configs.json /app/server/prisma/configs.json 2>/dev/null || echo "⚠️ Failed to copy configs.json"
cp -f /app/infra/providers.json /app/server/prisma/providers.json 2>/dev/null || echo "⚠️ Failed to copy providers.json"
cp -f /app/infra/check-missing.js /app/server/prisma/check-missing.js 2>/dev/null || echo "⚠️ Failed to copy check-missing.js"
if [ "$(id -u)" = "0" ]; then
chown $TARGET_UID:$TARGET_GID /app/server/prisma/configs.json /app/server/prisma/providers.json /app/server/prisma/check-missing.js 2>/dev/null || true
fi
fi
if [ ! -f "/app/server/prisma/palmr.db" ]; then
echo "🚀 First run detected - setting up database..."
echo "🗄️ Creating database schema..."
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID npx prisma db push --schema=./prisma/schema.prisma --skip-generate
else
npx prisma db push --schema=./prisma/schema.prisma --skip-generate
fi
run_as_user npx prisma db push --schema=./prisma/schema.prisma --skip-generate
echo "🌱 Seeding database..."
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID node ./prisma/seed.js
else
node ./prisma/seed.js
fi
run_as_user node ./prisma/seed.js
echo "✅ Database setup completed!"
else
echo "♻️ Existing database found"
echo "🔧 Checking for schema updates..."
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID npx prisma db push --schema=./prisma/schema.prisma --skip-generate
else
npx prisma db push --schema=./prisma/schema.prisma --skip-generate
fi
run_as_user npx prisma db push --schema=./prisma/schema.prisma --skip-generate
echo "🔍 Checking if new tables need seeding..."
NEEDS_SEEDING=$(
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function checkSeedingNeeded() {
try {
const appConfigCount = await prisma.appConfig.count();
const userCount = await prisma.user.count();
const authProviderCount = await prisma.authProvider.count();
if (appConfigCount === 0 || userCount === 0) {
console.log('true');
return;
}
if (authProviderCount === 0) {
console.log('true');
return;
}
const expectedProviders = ['google', 'discord', 'github', 'auth0', 'kinde', 'zitadel', 'authentik', 'frontegg', 'pocketid'];
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('true');
return;
}
console.log('false');
} catch (error) {
console.log('true');
} finally {
await prisma.\$disconnect();
}
}
checkSeedingNeeded();
" 2>/dev/null || echo "true"
else
node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function checkSeedingNeeded() {
try {
const appConfigCount = await prisma.appConfig.count();
const userCount = await prisma.user.count();
const authProviderCount = await prisma.authProvider.count();
if (appConfigCount === 0 || userCount === 0) {
console.log('true');
return;
}
if (authProviderCount === 0) {
console.log('true');
return;
}
const expectedProviders = ['google', 'discord', 'github', 'auth0', 'kinde', 'zitadel', 'authentik', 'frontegg', 'pocketid'];
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('true');
return;
}
console.log('false');
} catch (error) {
console.log('true');
} finally {
await prisma.\$disconnect();
}
}
checkSeedingNeeded();
" 2>/dev/null || echo "true"
fi
)
NEEDS_SEEDING=$(run_as_user node ./prisma/check-missing.js check-seeding 2>/dev/null || echo "true")
if [ "$NEEDS_SEEDING" = "true" ]; then
echo "🌱 New tables detected or missing data, running seed..."
# Check which providers are missing for better logging
MISSING_PROVIDERS=$(
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function checkMissingProviders() {
try {
const expectedProviders = ['google', 'discord', 'github', 'auth0', 'kinde', 'zitadel', 'authentik', 'frontegg', 'pocketid'];
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('Missing providers: ' + missingProviders.join(', '));
} else {
console.log('No missing providers');
}
} catch (error) {
console.log('Error checking providers');
} finally {
await prisma.\$disconnect();
}
}
checkMissingProviders();
" 2>/dev/null || echo "Error checking providers"
else
node -e "
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function checkMissingProviders() {
try {
const expectedProviders = ['google', 'discord', 'github', 'auth0', 'kinde', 'zitadel', 'authentik', 'frontegg', 'pocketid'];
const existingProviders = await prisma.authProvider.findMany({
select: { name: true }
});
const existingProviderNames = existingProviders.map(p => p.name);
const missingProviders = expectedProviders.filter(name => !existingProviderNames.includes(name));
if (missingProviders.length > 0) {
console.log('Missing providers: ' + missingProviders.join(', '));
} else {
console.log('No missing providers');
}
} catch (error) {
console.log('Error checking providers');
} finally {
await prisma.\$disconnect();
}
}
checkMissingProviders();
" 2>/dev/null || echo "Error checking providers"
fi
)
MISSING_PROVIDERS=$(run_as_user node ./prisma/check-missing.js check-providers 2>/dev/null || echo "Error checking providers")
MISSING_CONFIGS=$(run_as_user node ./prisma/check-missing.js check-configs 2>/dev/null || echo "Error checking configurations")
if [ "$MISSING_PROVIDERS" != "No missing providers" ] && [ "$MISSING_PROVIDERS" != "Error checking providers" ]; then
echo "🔍 $MISSING_PROVIDERS"
fi
if [ "$(id -u)" = "0" ]; then
su-exec $TARGET_UID:$TARGET_GID node ./prisma/seed.js
else
node ./prisma/seed.js
if [ "$MISSING_CONFIGS" != "No missing configurations" ] && [ "$MISSING_CONFIGS" != "Error checking configurations" ]; then
echo "⚙️ $MISSING_CONFIGS"
fi
run_as_user node ./prisma/seed.js
echo "✅ Seeding completed!"
else
echo "✅ All tables have data, no seeding needed"
@@ -242,4 +101,4 @@ if [ "$(id -u)" = "0" ]; then
exec su-exec $TARGET_UID:$TARGET_GID node dist/server.js
else
exec node dist/server.js
fi
fi