Skip to content

Commit 7de6e56

Browse files
committed
test(validation): add invalid timezone boundary checks
1 parent 572bfcc commit 7de6e56

2 files changed

Lines changed: 31 additions & 1 deletion

File tree

lib/validations.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,19 @@ describe('streakParamsSchema', () => {
347347
expect(result.data.delta_format).toBe('percent');
348348
}
349349
});
350+
351+
it('rejects invalid IANA timezone names', () => {
352+
const result = streakParamsSchema.safeParse({
353+
user: 'octocat',
354+
tz: 'Mars/Cyonia',
355+
});
356+
357+
expect(result.success).toBe(false);
358+
359+
if (!result.success) {
360+
expect(result.error.issues[0]?.message).toBe('Invalid timezone');
361+
}
362+
});
350363
});
351364

352365
it('should succeed when username contains hyphens', () => {

lib/validations.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ function dimensionParam(name: string, min: number, max: number) {
5858
.transform(toDimensionValue);
5959
}
6060

61+
function isValidTimeZone(tz?: string): boolean {
62+
if (!tz) return true;
63+
64+
try {
65+
Intl.DateTimeFormat(undefined, { timeZone: tz });
66+
return true;
67+
} catch {
68+
return false;
69+
}
70+
}
71+
72+
const timeZoneParam = z
73+
.string()
74+
.optional()
75+
.refine(isValidTimeZone, { message: 'Invalid timezone' });
76+
6177
const GITHUB_USERNAME_REGEX = /^[a-zA-Z0-9](?:[a-zA-Z0-9]|-(?=[a-zA-Z0-9]))*$/;
6278

6379
export const streakParamsSchema = z.object({
@@ -174,6 +190,7 @@ export const streakParamsSchema = z.object({
174190
hide_background: z.string().optional().transform(toBooleanFlag),
175191
hide_stats: z.string().optional().transform(toBooleanFlag),
176192
lang: z.string().optional().default('en'),
193+
tz: timeZoneParam,
177194
// Unknown view values fall back to the default dashboard view.
178195
view: z.enum(['default', 'monthly']).catch('default').default('default'),
179196
// Invalid delta formats fall back to percentage mode.
@@ -282,7 +299,7 @@ export const statsParamsSchema = z.object({
282299
message: 'Invalid GitHub username',
283300
}),
284301
refresh: z.string().optional().transform(toRefreshFlag),
285-
tz: z.string().optional(),
302+
tz: timeZoneParam,
286303
});
287304

288305
export const wrappedParamsSchema = z.object({

0 commit comments

Comments
 (0)