From d36ddf06f2f7cf51df43e72ef9ecc58e7528da3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:18:12 +0000 Subject: [PATCH 1/6] Fix URL validation and TypeScript deprecations --- Client/tsconfig.json | 1 + backend/lib/validations/profile.ts | 7 +++++-- backend/tsconfig.json | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Client/tsconfig.json b/Client/tsconfig.json index 2518773..131e1a1 100644 --- a/Client/tsconfig.json +++ b/Client/tsconfig.json @@ -3,6 +3,7 @@ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], "compilerOptions": { "baseUrl": ".", + "ignoreDeprecations": "6.0", "paths": { "@/*": ["./src/*"] }, diff --git a/backend/lib/validations/profile.ts b/backend/lib/validations/profile.ts index ff8e6c5..70f5048 100644 --- a/backend/lib/validations/profile.ts +++ b/backend/lib/validations/profile.ts @@ -1,5 +1,8 @@ import { z } from 'zod' +const httpUrlSchema = (message: string) => + z.string().regex(/^https?:\/\/.+/i, message) + /** * Profile update validation schema * Validates username, full_name, bio, github_url, linkedin_url, portfolio_url, and skills @@ -45,7 +48,6 @@ export const profileUpdateSchema = z.object({ graduation_year: z.union([z.number().int().min(1900).max(2100), z.string(), z.null()]).optional(), phone: z.string().max(20).optional().or(z.literal('')), address: z.string().max(200).optional().or(z.literal('')), - avatar_url: z.string().url().optional().or(z.literal('')), banner_url: z.string().regex(/^https?:\/\/.+/i, 'Banner URL must be a valid URL').optional().or(z.literal('')), interests: z.array(z.string()).max(10, 'Cannot have more than 10 interests').optional(), first_name: z.string().max(50).optional().or(z.literal('')), @@ -59,7 +61,8 @@ export const profileUpdateSchema = z.object({ degree_type: z.string().optional().or(z.literal('')), graduation_month: z.string().optional().or(z.literal('')), roles: z.array(z.string()).optional(), - resume_url: z.string().url().optional().or(z.literal('')), + avatar_url: httpUrlSchema('Avatar URL must be a valid URL').optional().or(z.literal('')), + resume_url: httpUrlSchema('Resume URL must be a valid URL').optional().or(z.literal('')), has_experience: z.boolean().optional(), twitter_url: z.string().regex(/^https?:\/\/.+/i, 'Twitter URL must be a valid URL').optional().or(z.literal('')), emergency_contact_name: z.string().max(100).optional().or(z.literal('')), diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 329679e..511473c 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -18,6 +18,7 @@ } ], "baseUrl": ".", + "ignoreDeprecations": "6.0", "paths": { "@/*": ["./*"] }, From c649f893d244ae27125f800ded4d62905372d32d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:21:11 +0000 Subject: [PATCH 2/6] Fix TypeScript deprecation suppression --- Client/tsconfig.json | 2 +- backend/tsconfig.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/tsconfig.json b/Client/tsconfig.json index 131e1a1..70227dc 100644 --- a/Client/tsconfig.json +++ b/Client/tsconfig.json @@ -3,7 +3,7 @@ "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], "compilerOptions": { "baseUrl": ".", - "ignoreDeprecations": "6.0", + "ignoreDeprecations": "5.0", "paths": { "@/*": ["./src/*"] }, diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 511473c..594a5d3 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -18,7 +18,7 @@ } ], "baseUrl": ".", - "ignoreDeprecations": "6.0", + "ignoreDeprecations": "5.0", "paths": { "@/*": ["./*"] }, From 8fd02ab362cdbb6b350f9d31ff328147cc38cff2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:23:03 +0000 Subject: [PATCH 3/6] Tighten profile URL validation --- backend/lib/validations/profile.ts | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/backend/lib/validations/profile.ts b/backend/lib/validations/profile.ts index 70f5048..05956b1 100644 --- a/backend/lib/validations/profile.ts +++ b/backend/lib/validations/profile.ts @@ -1,7 +1,7 @@ import { z } from 'zod' const httpUrlSchema = (message: string) => - z.string().regex(/^https?:\/\/.+/i, message) + z.string().regex(/^https?:\/\/[^\s]+$/i, message) /** * Profile update validation schema @@ -24,21 +24,9 @@ export const profileUpdateSchema = z.object({ .max(500, 'Bio must not exceed 500 characters') .optional() .or(z.literal('')), - github_url: z - .string() - .regex(/^https?:\/\/.+/i, 'GitHub URL must be a valid URL') - .optional() - .or(z.literal('')), - linkedin_url: z - .string() - .regex(/^https?:\/\/.+/i, 'LinkedIn URL must be a valid URL') - .optional() - .or(z.literal('')), - portfolio_url: z - .string() - .regex(/^https?:\/\/.+/i, 'Portfolio URL must be a valid URL') - .optional() - .or(z.literal('')), + github_url: httpUrlSchema('GitHub URL must be a valid URL').optional().or(z.literal('')), + linkedin_url: httpUrlSchema('LinkedIn URL must be a valid URL').optional().or(z.literal('')), + portfolio_url: httpUrlSchema('Portfolio URL must be a valid URL').optional().or(z.literal('')), skills: z .array(z.string()) .max(10, 'Cannot have more than 10 skills') @@ -48,7 +36,7 @@ export const profileUpdateSchema = z.object({ graduation_year: z.union([z.number().int().min(1900).max(2100), z.string(), z.null()]).optional(), phone: z.string().max(20).optional().or(z.literal('')), address: z.string().max(200).optional().or(z.literal('')), - banner_url: z.string().regex(/^https?:\/\/.+/i, 'Banner URL must be a valid URL').optional().or(z.literal('')), + banner_url: httpUrlSchema('Banner URL must be a valid URL').optional().or(z.literal('')), interests: z.array(z.string()).max(10, 'Cannot have more than 10 interests').optional(), first_name: z.string().max(50).optional().or(z.literal('')), last_name: z.string().max(50).optional().or(z.literal('')), @@ -64,7 +52,7 @@ export const profileUpdateSchema = z.object({ avatar_url: httpUrlSchema('Avatar URL must be a valid URL').optional().or(z.literal('')), resume_url: httpUrlSchema('Resume URL must be a valid URL').optional().or(z.literal('')), has_experience: z.boolean().optional(), - twitter_url: z.string().regex(/^https?:\/\/.+/i, 'Twitter URL must be a valid URL').optional().or(z.literal('')), + twitter_url: httpUrlSchema('Twitter URL must be a valid URL').optional().or(z.literal('')), emergency_contact_name: z.string().max(100).optional().or(z.literal('')), emergency_contact_phone: z.string().max(20).optional().or(z.literal('')), is_email_public: z.boolean().optional(), From 7eef55055933f807dcd5c9c77b5849597d5131f5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:24:22 +0000 Subject: [PATCH 4/6] Strengthen URL validation --- backend/lib/validations/profile.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/backend/lib/validations/profile.ts b/backend/lib/validations/profile.ts index 05956b1..b91f040 100644 --- a/backend/lib/validations/profile.ts +++ b/backend/lib/validations/profile.ts @@ -1,7 +1,25 @@ import { z } from 'zod' +const isValidHttpUrl = (value: string) => { + try { + const parsed = new URL(value) + if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') { + return false + } + + const hostname = parsed.hostname.toLowerCase() + return ( + hostname === 'localhost' || + hostname.includes('.') || + /^\d{1,3}(?:\.\d{1,3}){3}$/.test(hostname) + ) + } catch { + return false + } +} + const httpUrlSchema = (message: string) => - z.string().regex(/^https?:\/\/[^\s]+$/i, message) + z.string().trim().refine(isValidHttpUrl, message) /** * Profile update validation schema From e7b9d2780e96e445b244f0e0e5f3ce5fa02ed647 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:25:41 +0000 Subject: [PATCH 5/6] Refine URL hostname checks --- backend/lib/validations/profile.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/lib/validations/profile.ts b/backend/lib/validations/profile.ts index b91f040..1bb9d7f 100644 --- a/backend/lib/validations/profile.ts +++ b/backend/lib/validations/profile.ts @@ -1,4 +1,5 @@ import { z } from 'zod' +import { isIP } from 'node:net' const isValidHttpUrl = (value: string) => { try { @@ -8,11 +9,7 @@ const isValidHttpUrl = (value: string) => { } const hostname = parsed.hostname.toLowerCase() - return ( - hostname === 'localhost' || - hostname.includes('.') || - /^\d{1,3}(?:\.\d{1,3}){3}$/.test(hostname) - ) + return hostname === 'localhost' || hostname.includes('.') || isIP(hostname) > 0 } catch { return false } From af85bf5b3b398673ef66e3483a94a084ad25ce92 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 29 May 2026 15:27:26 +0000 Subject: [PATCH 6/6] Finalize profile URL checks --- backend/lib/validations/profile.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/lib/validations/profile.ts b/backend/lib/validations/profile.ts index 1bb9d7f..9e9a552 100644 --- a/backend/lib/validations/profile.ts +++ b/backend/lib/validations/profile.ts @@ -1,6 +1,10 @@ import { z } from 'zod' import { isIP } from 'node:net' +/** + * Validates public profile links. + * Accepts http/https URLs with a real hostname, localhost, or a valid IP address. + */ const isValidHttpUrl = (value: string) => { try { const parsed = new URL(value) @@ -9,7 +13,7 @@ const isValidHttpUrl = (value: string) => { } const hostname = parsed.hostname.toLowerCase() - return hostname === 'localhost' || hostname.includes('.') || isIP(hostname) > 0 + return hostname === 'localhost' || isIP(hostname) > 0 || /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/i.test(hostname) } catch { return false }