diff --git a/scripts/init-db.js b/scripts/init-db.js index c3d37ae..1417678 100644 --- a/scripts/init-db.js +++ b/scripts/init-db.js @@ -4,6 +4,26 @@ const { Pool } = require('pg') const fs = require('fs') const path = require('path') +// Load .env manually +try { + const envPath = path.join(__dirname, '..', '.env') + if (fs.existsSync(envPath)) { + const envConfig = fs.readFileSync(envPath, 'utf8') + envConfig.split('\n').forEach(line => { + const match = line.match(/^([^=]+)=(.*)$/) + if (match) { + const key = match[1].trim() + const value = match[2].trim().replace(/^["']|["']$/g, '') // remove quotes + if (!process.env[key]) { + process.env[key] = value + } + } + }) + } +} catch (e) { + console.error('Error loading .env', e) +} + const DB_HOST = process.env.DB_HOST || 'localhost' const DB_PORT = parseInt(process.env.DB_PORT || '5432', 10) const DB_USER = process.env.DB_USER || 'postgres' diff --git a/src/app/api/init-platforms/route.ts b/src/app/api/init-platforms/route.ts index 0bc1ca7..c96e3bb 100644 --- a/src/app/api/init-platforms/route.ts +++ b/src/app/api/init-platforms/route.ts @@ -1,7 +1,17 @@ -import { NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' import { PlatformInitializer } from '@/services/platformInitializer' +import { SyncAuth } from '@/lib/sync/auth' + +export async function POST(request: NextRequest) { + // Check auth + const auth = await SyncAuth.isWriteAllowed(request) + if (!auth.allowed) { + return NextResponse.json( + { error: auth.reason || 'Unauthorized' }, + { status: 403 } + ) + } -export async function POST() { try { await PlatformInitializer.initializePlatforms() return NextResponse.json({ diff --git a/src/app/api/packages/[id]/route.ts b/src/app/api/packages/[id]/route.ts index 2a54825..504ea30 100644 --- a/src/app/api/packages/[id]/route.ts +++ b/src/app/api/packages/[id]/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' import { PackageService } from '@/services/packageService' +import { SyncAuth } from '@/lib/sync/auth' export async function GET( request: NextRequest, @@ -54,6 +55,15 @@ export async function DELETE( request: NextRequest, { params }: { params: { id: string } } ) { + // Check auth + const auth = await SyncAuth.isWriteAllowed(request) + if (!auth.allowed) { + return NextResponse.json( + { error: auth.reason || 'Unauthorized' }, + { status: 403 } + ) + } + try { const success = await PackageService.delete(params.id) diff --git a/src/app/api/packages/route.ts b/src/app/api/packages/route.ts index f890c0f..4e2cafc 100644 --- a/src/app/api/packages/route.ts +++ b/src/app/api/packages/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from 'next/server' import { PackageService } from '@/services/packageService' +import { SyncAuth } from '@/lib/sync/auth' export async function GET(request: NextRequest) { try { @@ -40,6 +41,15 @@ export async function GET(request: NextRequest) { } export async function POST(request: NextRequest) { + // Check auth + const auth = await SyncAuth.isWriteAllowed(request) + if (!auth.allowed) { + return NextResponse.json( + { error: auth.reason || 'Unauthorized' }, + { status: 403 } + ) + } + try { const body = await request.json() const packageData = await PackageService.create(body) diff --git a/src/lib/sync/auth.ts b/src/lib/sync/auth.ts index 9a57ae3..f159d15 100644 --- a/src/lib/sync/auth.ts +++ b/src/lib/sync/auth.ts @@ -55,6 +55,43 @@ export class SyncAuth { return { allowed: true } } + /** + * Check if write operations (create/update/delete) are allowed + * ALWAYS requires authentication (secret key or localhost), ignoring SYNC_SERVER_ONLY + */ + static async isWriteAllowed(request: NextRequest): Promise<{ allowed: boolean; reason?: string }> { + // Always enforce auth for writes + const secretKey = request.headers.get('x-sync-secret') + + // Check localhost + const clientIP = request.headers.get('x-forwarded-for') || + request.headers.get('x-real-ip') || + 'unknown' + + const allowedIPs = ['127.0.0.1', 'localhost', '::1'] + const isLocalRequest = allowedIPs.includes(clientIP.split(',')[0].trim()) + + if (isLocalRequest) { + return { allowed: true } + } + + if (!this.SYNC_SECRET) { + return { + allowed: false, + reason: 'Secret key not configured on server' + } + } + + if (secretKey === this.SYNC_SECRET) { + return { allowed: true } + } + + return { + allowed: false, + reason: 'Write operations require authentication' + } + } + /** * Get automatic sync frequency in days */