Docker hardening + first-run fixes

This commit is contained in:
Christomatt
2026-02-05 02:49:34 +01:00
parent 38ddbf8bc1
commit a686db38b0
19 changed files with 346 additions and 53 deletions
+23 -4
View File
@@ -1,9 +1,16 @@
import { NextRequest, NextResponse } from 'next/server';
import { db, users } from '@/db';
import { db, users, isDbAvailable } from '@/db';
import { eq } from 'drizzle-orm';
export async function GET(req: NextRequest) {
try {
if (!isDbAvailable()) {
return NextResponse.json(
{ available: false, error: 'Database not configured' },
{ status: 503 }
);
}
const { searchParams } = new URL(req.url);
const handle = searchParams.get('handle')?.toLowerCase().trim();
@@ -15,9 +22,21 @@ export async function GET(req: NextRequest) {
return NextResponse.json({ available: false, error: 'Invalid characters' });
}
const existingUser = await db.query.users.findFirst({
where: eq(users.handle, handle),
});
let existingUser = null;
try {
existingUser = await db.query.users.findFirst({
where: eq(users.handle, handle),
});
} catch (err: any) {
// Handle fresh installs where the users table isn't created yet.
if (err?.code === '42P01' || /relation .*users.* does not exist/i.test(err?.message || '')) {
return NextResponse.json(
{ available: true, handle, warning: 'Database not initialized' },
{ status: 503 }
);
}
throw err;
}
return NextResponse.json({
available: !existingUser,
+29 -6
View File
@@ -1,12 +1,29 @@
import { NextResponse } from 'next/server';
import { NextRequest, NextResponse } from 'next/server';
import { db, nodes } from '@/db';
import { eq } from 'drizzle-orm';
export async function GET() {
function getRequestBaseUrl(req: NextRequest, fallbackDomain: string): string {
const forwardedHost = req.headers.get('x-forwarded-host');
const forwardedProto = req.headers.get('x-forwarded-proto');
const host = forwardedHost?.split(',')[0]?.trim() || req.headers.get('host');
const protocol =
forwardedProto?.split(',')[0]?.trim() ||
(host && host.includes('localhost') ? 'http' : 'https');
if (host) {
return `${protocol}://${host}`;
}
return `https://${fallbackDomain}`;
}
export async function GET(req: NextRequest) {
try {
if (!db) {
// Redirect to default favicon
return NextResponse.redirect(new URL('/favicon.png', process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'));
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const baseUrl = getRequestBaseUrl(req, domain);
return NextResponse.redirect(new URL('/favicon.png', baseUrl));
}
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
@@ -17,14 +34,20 @@ export async function GET() {
if (node?.faviconUrl) {
// Redirect to custom favicon
return NextResponse.redirect(node.faviconUrl);
const baseUrl = getRequestBaseUrl(req, domain);
const target = node.faviconUrl.startsWith('/')
? new URL(node.faviconUrl, baseUrl)
: node.faviconUrl;
return NextResponse.redirect(target);
}
// Redirect to default favicon
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || `https://${domain}`;
const baseUrl = getRequestBaseUrl(req, domain);
return NextResponse.redirect(new URL('/favicon.png', baseUrl));
} catch (error) {
console.error('Favicon error:', error);
return NextResponse.redirect(new URL('/favicon.png', process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'));
const domain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const baseUrl = getRequestBaseUrl(req, domain);
return NextResponse.redirect(new URL('/favicon.png', baseUrl));
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ export async function POST(req: NextRequest) {
accessKeyId: process.env.STORAGE_ACCESS_KEY || '',
secretAccessKey: process.env.STORAGE_SECRET_KEY || '',
},
forcePathStyle: true, // Needed for many S3-compatible providers (MinIO, etc.)
forcePathStyle: true, // Needed for many S3-compatible providers
});
const bucket = process.env.STORAGE_BUCKET || 'synapsis';