mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-12 09:56:08 +00:00
feat(auth): enforce length limits for name and password during registration
feat(comments): add content length validation for comments and annotations feat(guest-gate): restrict guest name length and update localStorage handling feat(share-link-unlock): set maxLength for password input field
This commit is contained in:
@@ -21,8 +21,8 @@ export async function POST(request: NextRequest) {
|
|||||||
const { name, email, password, inviteCode, invitationToken } = body;
|
const { name, email, password, inviteCode, invitationToken } = body;
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!name || typeof name !== 'string' || name.trim().length < 2) {
|
if (!name || typeof name !== 'string' || name.trim().length < 2 || name.trim().length > 100) {
|
||||||
return apiErrors.badRequest('Name must be at least 2 characters');
|
return apiErrors.badRequest('Name must be between 2 and 100 characters');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!email || typeof email !== 'string') {
|
if (!email || typeof email !== 'string') {
|
||||||
@@ -72,8 +72,8 @@ export async function POST(request: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!password || typeof password !== 'string' || password.length < 8) {
|
if (!password || typeof password !== 'string' || password.length < 8 || password.length > 128) {
|
||||||
return apiErrors.badRequest('Password must be at least 8 characters');
|
return apiErrors.badRequest('Password must be between 8 and 128 characters');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if email already exists
|
// Check if email already exists
|
||||||
|
|||||||
@@ -252,6 +252,17 @@ export async function POST(request: NextRequest, { params }: RouteParams) {
|
|||||||
return apiErrors.badRequest('Either content, a voice recording, an image attachment, or an annotation is required');
|
return apiErrors.badRequest('Either content, a voice recording, an image attachment, or an annotation is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Length limits to prevent DB bloat and DoS on export/notification paths
|
||||||
|
if (content !== undefined && content !== null && String(content).length > 10_000) {
|
||||||
|
return apiErrors.badRequest('Comment content must be 10,000 characters or fewer');
|
||||||
|
}
|
||||||
|
if (guestName !== undefined && guestName !== null && String(guestName).length > 100) {
|
||||||
|
return apiErrors.badRequest('Guest name must be 100 characters or fewer');
|
||||||
|
}
|
||||||
|
if (annotationData !== undefined && annotationData !== null && JSON.stringify(annotationData).length > 50_000) {
|
||||||
|
return apiErrors.badRequest('Annotation data is too large');
|
||||||
|
}
|
||||||
|
|
||||||
// If replying, verify parent exists in same version
|
// If replying, verify parent exists in same version
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
const parent = await db.comment.findFirst({
|
const parent = await db.comment.findFirst({
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ export function GuestGate({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const confirm = () => {
|
const confirm = () => {
|
||||||
if (!guestName.trim()) return;
|
const trimmed = guestName.trim();
|
||||||
localStorage.setItem('openframe_guest_name', guestName.trim());
|
if (!trimmed || trimmed.length > 100) return;
|
||||||
|
localStorage.setItem('openframe_guest_name', trimmed);
|
||||||
setConfirmed(true);
|
setConfirmed(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,13 +48,14 @@ export function GuestGate({ children }: { children: ReactNode }) {
|
|||||||
<Input
|
<Input
|
||||||
placeholder="Your name"
|
placeholder="Your name"
|
||||||
value={guestName}
|
value={guestName}
|
||||||
|
maxLength={100}
|
||||||
onChange={(e) => setGuestName(e.target.value)}
|
onChange={(e) => setGuestName(e.target.value)}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') confirm();
|
if (e.key === 'Enter') confirm();
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<Button className="w-full" disabled={!guestName.trim()} onClick={confirm}>
|
<Button className="w-full" disabled={!guestName.trim() || guestName.trim().length > 100} onClick={confirm}>
|
||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export function ShareLinkUnlock({ videoId }: ShareLinkUnlockProps) {
|
|||||||
type="password"
|
type="password"
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
value={password}
|
value={password}
|
||||||
|
maxLength={128}
|
||||||
onChange={(event) => setPassword(event.target.value)}
|
onChange={(event) => setPassword(event.target.value)}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
|
|||||||
Reference in New Issue
Block a user