← back to Wine Finder Next
app/api/membership/marketplace/route.ts
137 lines
import { NextRequest, NextResponse } from 'next/server';
import { marketplaceDb } from '@/lib/membershipDatabase';
import type { ApiResponse } from '@/src/types/membership';
import { checkRateLimit, getRateLimitConfig, getClientIdentifier } from '@/lib/rateLimit';
import { logAudit } from '@/lib/auth';
import { sanitizeString, validateUserId, validatePrice, validateQuantity } from '@/lib/inputValidation';
import { analyzeRequest } from '@/lib/securityMonitoring';
export async function GET(request: NextRequest) {
try {
// Rate limiting
const identifier = getClientIdentifier(request);
const rateLimit = checkRateLimit(identifier, getRateLimitConfig('/api/membership/marketplace'));
if (!rateLimit.success) {
return NextResponse.json({
success: false,
error: 'Rate limit exceeded. Please try again later.'
} as ApiResponse<null>, { status: 429 });
}
const { searchParams } = new URL(request.url);
const activeOnly = searchParams.get('active') === 'true';
const sellerId = searchParams.get('sellerId');
// Validate sellerId if provided
if (sellerId) {
const sanitizedSellerId = sanitizeString(sellerId, 100);
if (!validateUserId(sanitizedSellerId)) {
return NextResponse.json({
success: false,
error: 'Invalid seller ID format'
} as ApiResponse<null>, { status: 400 });
}
}
let listings;
if (activeOnly) {
listings = marketplaceDb.getActive();
} else if (sellerId) {
listings = marketplaceDb.getBySellerId(sanitizeString(sellerId, 100));
} else {
listings = marketplaceDb.getAll();
}
logAudit({
action: 'MARKETPLACE_LIST',
resource: 'marketplace',
ipAddress: identifier,
userAgent: request.headers.get('user-agent') || 'unknown',
success: true,
metadata: { count: listings.length, sellerId, activeOnly }
});
return NextResponse.json({
success: true,
data: listings
} as ApiResponse<typeof listings>);
} catch (error) {
return NextResponse.json({
success: false,
error: 'Failed to fetch marketplace listings'
} as ApiResponse<null>, { status: 500 });
}
}
export async function POST(request: NextRequest) {
try {
// Rate limiting
const identifier = getClientIdentifier(request);
const rateLimit = checkRateLimit(identifier, getRateLimitConfig('/api/membership/marketplace'));
if (!rateLimit.success) {
return NextResponse.json({
success: false,
error: 'Rate limit exceeded. Please try again later.'
} as ApiResponse<null>, { status: 429 });
}
// Threat detection
const body = await request.json();
const analysis = analyzeRequest({
body,
headers: Object.fromEntries(request.headers),
ip: identifier
});
if (!analysis.safe) {
return NextResponse.json({
success: false,
error: 'Security threat detected'
} as ApiResponse<null>, { status: 403 });
}
// Validate and sanitize
if (body.sellerId && !validateUserId(body.sellerId)) {
return NextResponse.json({
success: false,
error: 'Invalid seller ID format'
} as ApiResponse<null>, { status: 400 });
}
if (body.price && !validatePrice(body.price)) {
return NextResponse.json({
success: false,
error: 'Invalid price format'
} as ApiResponse<null>, { status: 400 });
}
const newListing = marketplaceDb.create(body);
logAudit({
action: 'MARKETPLACE_CREATE',
resource: `marketplace/${newListing.id}`,
ipAddress: identifier,
userAgent: request.headers.get('user-agent') || 'unknown',
success: true,
metadata: {
listingId: newListing.id,
sellerId: newListing.sellerId,
price: newListing.price
}
});
return NextResponse.json({
success: true,
data: newListing,
message: 'Listing created successfully'
} as ApiResponse<typeof newListing>);
} catch (error) {
return NextResponse.json({
success: false,
error: 'Failed to create listing'
} as ApiResponse<null>, { status: 500 });
}
}