mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
fix: harden email validation and CI permissions
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
isEmailVerificationEnabled,
|
||||
sendVerificationEmail,
|
||||
} from '@/lib/email-verification';
|
||||
import { isValidEmailAddress, normalizeEmail } from '@/lib/email-validation';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
@@ -39,11 +40,10 @@ export async function POST(request: NextRequest) {
|
||||
if (!email || typeof email !== 'string') {
|
||||
return apiErrors.badRequest('Email is required');
|
||||
}
|
||||
const normalizedEmail = email.toLowerCase().trim();
|
||||
const normalizedEmail = normalizeEmail(email);
|
||||
|
||||
// Basic email validation
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(normalizedEmail)) {
|
||||
if (!isValidEmailAddress(normalizedEmail)) {
|
||||
return apiErrors.validationError('Invalid email format');
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
sendVerificationEmail,
|
||||
} from '@/lib/email-verification';
|
||||
import { logError } from '@/lib/logger';
|
||||
import { isValidEmailAddress, normalizeEmail } from '@/lib/email-validation';
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
@@ -28,14 +29,13 @@ export async function POST(request: NextRequest) {
|
||||
const body = await request.json();
|
||||
const { email } = body;
|
||||
|
||||
if (!email || typeof email !== 'string' || email.length > 254 || !email.includes('@')) {
|
||||
if (!email || typeof email !== 'string') {
|
||||
return apiErrors.badRequest('Valid email is required');
|
||||
}
|
||||
|
||||
const normalizedEmail = email.toLowerCase().trim();
|
||||
const normalizedEmail = normalizeEmail(email);
|
||||
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(normalizedEmail)) {
|
||||
if (!isValidEmailAddress(normalizedEmail)) {
|
||||
return apiErrors.badRequest('Valid email is required');
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@/lib/invitations';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
import { logError } from '@/lib/logger';
|
||||
import { isValidEmailAddress, normalizeEmail } from '@/lib/email-validation';
|
||||
|
||||
type RouteParams = { params: Promise<{ projectId: string }> };
|
||||
|
||||
@@ -126,9 +127,8 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
return apiErrors.badRequest('Email is required');
|
||||
}
|
||||
|
||||
const normalizedEmail = email.toLowerCase().trim();
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(normalizedEmail)) {
|
||||
const normalizedEmail = normalizeEmail(email);
|
||||
if (!isValidEmailAddress(normalizedEmail)) {
|
||||
return apiErrors.validationError('Invalid email format');
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { validateAnnotationStrokes } from '@/lib/validation';
|
||||
import { logError } from '@/lib/logger';
|
||||
import { reserveStorageQuota, releaseStorageReservation } from '@/lib/storage-quota';
|
||||
import { isValidEmailAddress, normalizeEmail } from '@/lib/email-validation';
|
||||
|
||||
type RouteParams = { params: Promise<{ versionId: string }> };
|
||||
const SAFE_IMAGE_PATH =
|
||||
@@ -328,14 +329,10 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
if (guestName !== undefined && guestName !== null && String(guestName).length > 100) {
|
||||
return apiErrors.badRequest('Guest name must be 100 characters or fewer');
|
||||
}
|
||||
let normalizedGuestEmail: string | null = null;
|
||||
if (guestEmail !== undefined && guestEmail !== null) {
|
||||
const emailStr = String(guestEmail);
|
||||
if (emailStr.length > 254) {
|
||||
return apiErrors.badRequest('Guest email must be 254 characters or fewer');
|
||||
}
|
||||
// RFC 5321 / HTML5 email pattern — simple but sufficient for a stored-value guard
|
||||
const emailRe = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRe.test(emailStr)) {
|
||||
normalizedGuestEmail = normalizeEmail(String(guestEmail));
|
||||
if (!isValidEmailAddress(normalizedGuestEmail)) {
|
||||
return apiErrors.badRequest('Guest email must be a valid email address');
|
||||
}
|
||||
}
|
||||
@@ -444,7 +441,7 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
annotationData: serializedAnnotationData,
|
||||
authorId: session?.user?.id || null,
|
||||
guestName: isGuest ? guestName : null,
|
||||
guestEmail: isGuest ? guestEmail : null,
|
||||
guestEmail: isGuest ? normalizedGuestEmail : null,
|
||||
guestIdentityId: isGuest ? (guestIdentity?.identityId ?? null) : null,
|
||||
tagId: tagId || null,
|
||||
versionId,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from '@/lib/invitations';
|
||||
import { apiErrors, successResponse, withCacheControl } from '@/lib/api-response';
|
||||
import { logError } from '@/lib/logger';
|
||||
import { isValidEmailAddress, normalizeEmail } from '@/lib/email-validation';
|
||||
|
||||
type RouteParams = { params: Promise<{ workspaceId: string }> };
|
||||
|
||||
@@ -168,9 +169,8 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
||||
return apiErrors.badRequest('Email is required');
|
||||
}
|
||||
|
||||
const normalizedEmail = email.toLowerCase().trim();
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(normalizedEmail)) {
|
||||
const normalizedEmail = normalizeEmail(email);
|
||||
if (!isValidEmailAddress(normalizedEmail)) {
|
||||
return apiErrors.validationError('Invalid email format');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user