fix: contact length limits + logger/next.config nitpicks + dep updates
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
CI Pipeline with Test Management / 🧪 Run Tests & Generate Reports (push) Waiting to run
CI Pipeline with Test Management / 🐳 Docker Integration Tests (push) Blocked by required conditions
CI Pipeline with Test Management / 🏗️ Build Docker Image (push) Blocked by required conditions
CI Pipeline with Test Management / 📊 Generate Test Summary (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🧪 Run Tests & Generate Reports (push) Waiting to run
Test Reporting & Gherkin Analysis / 📊 Analyze Test Coverage (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / 🔄 Sync with Linear (push) Blocked by required conditions
Test Reporting & Gherkin Analysis / ⚡ Performance Monitoring (push) Blocked by required conditions
- /api/contact enforces per-field length caps (name/email/subject/message) before sanitization/persistence; over-long message returns 400 without touching Mongo (test added) - logger: crypto-based request id (randomUUID) instead of Math.random().substr; defaultMeta.version prefers DEPLOY_VERSION over npm_package_version - next.config: move Turbopack svg rule from deprecated experimental.turbo to top-level turbopack - deps: bump next 15.5.2 → 15.5.23; npm audit fix (19 → 3, remaining are transitive sharp/libvips DoS advisories, not exploitable for static images) Closes MITHOME-78, MITHOME-79
This commit is contained in:
@@ -14,15 +14,13 @@ const nextConfig: NextConfig = {
|
|||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Optimize for production builds
|
// Optimize for production builds — Turbopack rules moved from the deprecated
|
||||||
experimental: {
|
// experimental.turbo to the top-level turbopack key (Next 15.5).
|
||||||
// Enable turbo mode for faster builds
|
turbopack: {
|
||||||
turbo: {
|
rules: {
|
||||||
rules: {
|
'*.svg': {
|
||||||
'*.svg': {
|
loaders: ['@svgr/webpack'],
|
||||||
loaders: ['@svgr/webpack'],
|
as: '*.js',
|
||||||
as: '*.js',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+453
-453
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -32,7 +32,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mongodb": "^6.5",
|
"mongodb": "^6.5",
|
||||||
"mongoose": "^8.2",
|
"mongoose": "^8.2",
|
||||||
"next": "15.5.2",
|
"next": "^15.5.23",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0"
|
"react-dom": "19.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -50,6 +50,23 @@ function sanitizeInput(input: string): string {
|
|||||||
return input.trim().replace(/[<>]/g, '')
|
return input.trim().replace(/[<>]/g, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WHY: explicit length caps — the CMS has a body limit but this public endpoint
|
||||||
|
// does not; without them an arbitrarily large message could be written to Mongo.
|
||||||
|
const MAX_LENGTHS = {
|
||||||
|
name: 100,
|
||||||
|
email: 254,
|
||||||
|
subject: 200,
|
||||||
|
message: 5000,
|
||||||
|
} as const
|
||||||
|
|
||||||
|
function validateLengths(data: ContactFormData): string | null {
|
||||||
|
if (data.name.length > MAX_LENGTHS.name) return 'A név túl hosszú.'
|
||||||
|
if (data.email.length > MAX_LENGTHS.email) return 'Az email cím túl hosszú.'
|
||||||
|
if (data.subject.length > MAX_LENGTHS.subject) return 'A tárgy túl hosszú.'
|
||||||
|
if (data.message.length > MAX_LENGTHS.message) return 'Az üzenet túl hosszú.'
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
// Get client IP for rate limiting
|
// Get client IP for rate limiting
|
||||||
@@ -75,6 +92,12 @@ export async function POST(request: NextRequest) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enforce field length caps before sanitization/persistence
|
||||||
|
const lengthError = validateLengths(body)
|
||||||
|
if (lengthError) {
|
||||||
|
return NextResponse.json({ error: lengthError }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
// Validate email format
|
// Validate email format
|
||||||
if (!validateEmail(body.email)) {
|
if (!validateEmail(body.email)) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -64,6 +64,19 @@ describe('/api/contact Unit Tests', () => {
|
|||||||
expect(response.status).toBe(500)
|
expect(response.status).toBe(500)
|
||||||
expect(mockInsertOne).toHaveBeenCalledTimes(1)
|
expect(mockInsertOne).toHaveBeenCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('rejects an over-long message before persisting', async () => {
|
||||||
|
const longMessage = { ...validData, message: 'x'.repeat(5001) }
|
||||||
|
const request = {
|
||||||
|
headers: new Headers({ 'x-forwarded-for': 'too-long' }),
|
||||||
|
json: async () => longMessage,
|
||||||
|
} as any
|
||||||
|
|
||||||
|
const response = await POST(request)
|
||||||
|
|
||||||
|
expect(response.status).toBe(400)
|
||||||
|
expect(mockInsertOne).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// TC-001: Email Format Validation Test (ZEE-48)
|
// TC-001: Email Format Validation Test (ZEE-48)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import winston from 'winston'
|
import winston from 'winston'
|
||||||
import LokiTransport from 'winston-loki'
|
import LokiTransport from 'winston-loki'
|
||||||
|
import { randomUUID } from 'crypto'
|
||||||
|
|
||||||
const isDevelopment = process.env.NODE_ENV === 'development'
|
const isDevelopment = process.env.NODE_ENV === 'development'
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@ export const logger = winston.createLogger({
|
|||||||
format: structuredFormat,
|
format: structuredFormat,
|
||||||
defaultMeta: {
|
defaultMeta: {
|
||||||
service: 'mozdit-web',
|
service: 'mozdit-web',
|
||||||
version: process.env.npm_package_version || '1.0.0',
|
version: process.env.DEPLOY_VERSION || process.env.npm_package_version || '1.0.0',
|
||||||
environment: process.env.NODE_ENV || 'development'
|
environment: process.env.NODE_ENV || 'development'
|
||||||
},
|
},
|
||||||
transports,
|
transports,
|
||||||
@@ -85,7 +86,7 @@ export const errorLogger = logger.child({ component: 'error' })
|
|||||||
|
|
||||||
// Request ID generator for correlation
|
// Request ID generator for correlation
|
||||||
export const generateRequestId = (): string =>
|
export const generateRequestId = (): string =>
|
||||||
`${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
|
`${Date.now()}-${randomUUID().slice(0, 8)}`
|
||||||
|
|
||||||
// Helper function for timing operations
|
// Helper function for timing operations
|
||||||
export const withTiming = async <T>(
|
export const withTiming = async <T>(
|
||||||
|
|||||||
Reference in New Issue
Block a user