Skip to content

Commit 01c9f14

Browse files
eshaanagkali
authored andcommitted
fix(api): reject reversed custom streak date ranges
1 parent a6b5fda commit 01c9f14

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

app/api/streak/route.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,19 @@ describe('GET /api/streak', () => {
531531
});
532532
});
533533

534+
it('returns 400 when custom from date is after custom to date', async () => {
535+
const response = await GET(
536+
makeRequest({ user: 'octocat', from: '2025-12-31', to: '2025-01-01' })
537+
);
538+
const body = await response.json();
539+
540+
expect(response.status).toBe(400);
541+
expect(body.details.fieldErrors.to[0]).toContain(
542+
'"to" date must be after or equal to "from" date'
543+
);
544+
expect(fetchGitHubContributions).not.toHaveBeenCalled();
545+
});
546+
534547
it('functions normally when the year parameter is missing', async () => {
535548
const response = await GET(makeRequest({ user: 'octocat' }));
536549

app/api/wrapped/route.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,14 @@ describe('GET /api/wrapped', () => {
150150
expect(response.status).toBe(200);
151151
expect(body).toContain('rx="15"');
152152
});
153+
154+
it('hides the wrapped badge background when hide_background=1 is passed', async () => {
155+
const response = await GET(makeRequest({ user: 'octocat', hide_background: '1' }));
156+
const body = await response.text();
157+
158+
expect(response.status).toBe(200);
159+
expect(body).toContain('fill="transparent"');
160+
});
153161
});
154162

155163
describe('cache-control header', () => {

lib/validations.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function dimensionParam(name: string, min: number, max: number) {
6060

6161
const GITHUB_USERNAME_REGEX = /^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9]))*$/;
6262

63-
export const streakParamsSchema = z.object({
63+
const baseStreakParamsSchema = z.object({
6464
// Required — missing user surfaces as "Missing" to match existing tests
6565
user: z
6666
.string({ error: 'Missing user parameter' })
@@ -243,6 +243,14 @@ export const streakParamsSchema = z.object({
243243
entrance: z.enum(['rise', 'fade', 'slide', 'none']).catch('rise').default('rise'),
244244
});
245245

246+
export const streakParamsSchema = baseStreakParamsSchema.refine(
247+
(data) => !data.from || !data.to || Date.parse(data.from) <= Date.parse(data.to),
248+
{
249+
message: '"to" date must be after or equal to "from" date',
250+
path: ['to'],
251+
}
252+
);
253+
246254
export const githubParamsSchema = z.object({
247255
username: z
248256
.string({ error: 'Missing "username" parameter' })

0 commit comments

Comments
 (0)