diff --git a/server/middleware/internal-auth.ts b/server/middleware/internal-auth.ts new file mode 100644 index 0000000..4d8641c --- /dev/null +++ b/server/middleware/internal-auth.ts @@ -0,0 +1,53 @@ +/** + * Basic Authentication Middleware for /internal/* routes + * Protects internal pages (styleguide, admin tools) with HTTP Basic Auth + */ + +export default defineEventHandler((event) => { + const path = event.path + + // Only protect /internal/* routes + if (!path.startsWith('/internal')) { + return + } + + const config = useRuntimeConfig() + + // Get credentials from environment variables + const validUsername = config.internalAuthUsername + const validPassword = config.internalAuthPassword + + // Skip auth if credentials are not configured (development convenience) + if (!validUsername || !validPassword) { + console.warn('⚠️ INTERNAL_AUTH_USERNAME or INTERNAL_AUTH_PASSWORD not set. /internal routes are unprotected!') + return + } + + // Get Authorization header + const authHeader = getHeader(event, 'authorization') + + if (!authHeader || !authHeader.startsWith('Basic ')) { + // Request authentication + setHeader(event, 'WWW-Authenticate', 'Basic realm="Internal Area"') + throw createError({ + statusCode: 401, + statusMessage: 'Authentication required', + }) + } + + // Decode credentials + const base64Credentials = authHeader.split(' ')[1] + const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8') + const [username, password] = credentials.split(':') + + // Validate credentials + if (username !== validUsername || password !== validPassword) { + setHeader(event, 'WWW-Authenticate', 'Basic realm="Internal Area"') + throw createError({ + statusCode: 401, + statusMessage: 'Invalid credentials', + }) + } + + // Authentication successful, continue +}) diff --git a/server/utils/db.ts b/server/utils/db.ts new file mode 100644 index 0000000..505eab2 --- /dev/null +++ b/server/utils/db.ts @@ -0,0 +1,34 @@ +import { drizzle } from 'drizzle-orm/postgres-js' +import postgres from 'postgres' +import * as schema from '../database/schema' + +/** + * Database connection utility + * + * Creates a singleton Drizzle ORM instance with the complete schema. + * This allows for type-safe database queries throughout the application. + * + * Usage: + * ```typescript + * import { db } from '~/server/utils/db' + * + * // Query with relations + * const users = await db.query.users.findMany({ + * with: { orders: true } + * }) + * + * // Raw SQL with type safety + * import { users } from '~/server/database/schema' + * import { eq } from 'drizzle-orm' + * + * const user = await db.select().from(users).where(eq(users.id, userId)) + * ``` + */ + +const config = useRuntimeConfig() + +// Create postgres.js client +const client = postgres(config.databaseUrl) + +// Create Drizzle ORM instance with schema +export const db = drizzle(client, { schema })