79 lines
2.0 KiB
TypeScript
79 lines
2.0 KiB
TypeScript
import { sanitizeHtml, validateDomain } from './security'
|
|
|
|
export function sanitizeUrl(url: string): string {
|
|
return sanitizeHtml(url.trim().substring(0, 2048))
|
|
}
|
|
|
|
export function validateEmail(email: string): boolean {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
return emailRegex.test(email) && email.length <= 254
|
|
}
|
|
|
|
export function validateUrl(url: string): boolean {
|
|
try {
|
|
const sanitized = sanitizeUrl(url)
|
|
if (!sanitized) return false
|
|
|
|
// Add protocol if missing
|
|
let testUrl = sanitized
|
|
if (!testUrl.startsWith('http://') && !testUrl.startsWith('https://')) {
|
|
testUrl = 'https://' + testUrl
|
|
}
|
|
|
|
const urlObj = new URL(testUrl)
|
|
|
|
// Check for suspicious patterns
|
|
const suspiciousPatterns = [
|
|
/javascript:/i,
|
|
/data:/i,
|
|
/vbscript:/i,
|
|
/file:/i,
|
|
/about:/i
|
|
]
|
|
|
|
return !suspiciousPatterns.some(pattern => pattern.test(testUrl))
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
export function validateRiskLevel(level: any): boolean {
|
|
const num = parseInt(level)
|
|
return !isNaN(num) && num >= 1 && num <= 5
|
|
}
|
|
|
|
export function escapeSql(input: string): string {
|
|
return input.replace(/'/g, "''")
|
|
}
|
|
|
|
export interface ValidationResult {
|
|
valid: boolean
|
|
errors: string[]
|
|
}
|
|
|
|
export function validateReportData(data: any): ValidationResult {
|
|
const errors: string[] = []
|
|
|
|
if (!data.source_url || typeof data.source_url !== 'string') {
|
|
errors.push('Source URL is required')
|
|
} else if (!validateUrl(data.source_url)) {
|
|
errors.push('Invalid URL format')
|
|
}
|
|
|
|
if (data.reporter_email && !validateEmail(data.reporter_email)) {
|
|
errors.push('Invalid email format')
|
|
}
|
|
|
|
if (!data.categories || !Array.isArray(data.categories) || data.categories.length === 0) {
|
|
errors.push('At least one category is required')
|
|
}
|
|
|
|
if (data.description && typeof data.description === 'string' && data.description.length > 1000) {
|
|
errors.push('Description too long (max 1000 characters)')
|
|
}
|
|
|
|
return {
|
|
valid: errors.length === 0,
|
|
errors
|
|
}
|
|
} |