mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-24 15:07:17 +00:00
fix: reject feedback origins longer than the source_origin column
readTargetParam accepted values up to 3000 chars but the raw origin is stored verbatim into source_origin VARCHAR(2048) (MySQL/Postgres), so a 2049-3000 char origin passed every validation and then blew up the INSERT with an HTTP 500 on Postgres/strict MySQL — or was silently truncated on non-strict MySQL, corrupting the abuse-forensics value the column exists for. Cap the param at the column size.
This commit is contained in:
@@ -357,6 +357,20 @@ describe('AppFeedbackController POST /', () => {
|
||||
).rejects.toMatchObject({ statusCode: 400 });
|
||||
});
|
||||
|
||||
it('throws 400 when the origin exceeds the stored column size', async () => {
|
||||
// source_origin is VARCHAR(2048) on MySQL/Postgres; a longer origin
|
||||
// must be rejected up front, not fail (or silently truncate) at the
|
||||
// INSERT after passing every other validation.
|
||||
mockEmailConfigured();
|
||||
const { userId: ownerId } = await makeUser();
|
||||
const app = await makeApp(ownerId, { feedbackEnabled: true });
|
||||
const origin = `${new URL(app.index_url).origin}/${'x'.repeat(2500)}`;
|
||||
const { actor } = await makeUser();
|
||||
await expect(
|
||||
submit(actor, { origin, message: 'hi' }),
|
||||
).rejects.toMatchObject({ statusCode: 400 });
|
||||
});
|
||||
|
||||
it('throws 403 feedback_not_enabled when the app has not opted in', async () => {
|
||||
mockEmailConfigured();
|
||||
const { userId: ownerId } = await makeUser();
|
||||
|
||||
@@ -38,8 +38,16 @@ import { PuterController } from '../types.js';
|
||||
/** Sanity cap on the raw body field; the service enforces the real limit. */
|
||||
const RAW_MESSAGE_CAP = 50_000;
|
||||
|
||||
// Upper bound on the `app`/`origin` target params. Must not exceed the
|
||||
// `source_origin` column (VARCHAR(2048) on MySQL/Postgres): the raw origin is
|
||||
// stored verbatim, and a longer value would fail the INSERT after passing
|
||||
// every validation — or be silently truncated on non-strict MySQL.
|
||||
const TARGET_PARAM_MAX_LENGTH = 2048;
|
||||
|
||||
const readTargetParam = (value: unknown): string | undefined => {
|
||||
return typeof value === 'string' && value.length > 0 && value.length <= 3000
|
||||
return typeof value === 'string' &&
|
||||
value.length > 0 &&
|
||||
value.length <= TARGET_PARAM_MAX_LENGTH
|
||||
? value
|
||||
: undefined;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user