diff --git a/src/Client/src/app/pages/company/editor/editor.component.html b/src/Client/src/app/pages/company/editor/editor.component.html index 8b85075..04eda5b 100644 --- a/src/Client/src/app/pages/company/editor/editor.component.html +++ b/src/Client/src/app/pages/company/editor/editor.component.html @@ -22,7 +22,7 @@
- +
diff --git a/src/Client/src/app/pages/company/editor/editor.component.ts b/src/Client/src/app/pages/company/editor/editor.component.ts index 41eab5e..46fe59f 100644 --- a/src/Client/src/app/pages/company/editor/editor.component.ts +++ b/src/Client/src/app/pages/company/editor/editor.component.ts @@ -62,9 +62,12 @@ export class CompanyEditorComponent { validateEmail(input: string){ let result = this.validator.validateEmail(input); - if (result[0]){ - this.newListing.email = result[1]; - } + this.newListing.email = result[1]; + } + + validateURL(input: string){ + let result = this.validator.validateURL(input); + this.newListing.websiteURL = result[1]; } @HostListener('window:keydown', ['$event']) @@ -146,6 +149,12 @@ export class CompanyEditorComponent { return; } + if (this.validator.validateURL(company.websiteURL)[0]){ + this.ErrorMsg = "Website is invalid"; + this.focusFrame(3, 1); + return; + } + if (this.isNullOrEmpty(company.logo)){ this.ErrorMsg = "Logo is blank"; this.focusFrame(2, 0); diff --git a/src/Client/src/app/pages/resumes/editor/editor.component.html b/src/Client/src/app/pages/resumes/editor/editor.component.html index c3ce681..31ba357 100644 --- a/src/Client/src/app/pages/resumes/editor/editor.component.html +++ b/src/Client/src/app/pages/resumes/editor/editor.component.html @@ -5,7 +5,6 @@

Public:

Is Veteran:

-
@@ -140,7 +139,7 @@
- +
@@ -156,7 +155,7 @@
- +
diff --git a/src/Client/src/app/pages/resumes/editor/editor.component.ts b/src/Client/src/app/pages/resumes/editor/editor.component.ts index f4c8ee9..4536848 100644 --- a/src/Client/src/app/pages/resumes/editor/editor.component.ts +++ b/src/Client/src/app/pages/resumes/editor/editor.component.ts @@ -90,32 +90,22 @@ export class ResumesEditorComponent { validatePhone(input: string){ let result = this.validator.validatePhoneNumber(input); - if (result[0]){ - this.resume.phoneNumber = result[1]; - } + this.resume.phoneNumber = result[1]; } validateEmail(input: string){ let result = this.validator.validateEmail(input); - if (result[0]){ - this.resume.email = result[1]; - } + this.resume.email = result[1]; } - PrintResume(){ - const divToPrint = document.getElementsByClassName("paper")[0]; + validateCertURL(input: ResumeCertification){ + let result = this.validator.validateURL(input.verificationURL); + input.verificationURL = result[1]; + } - const printContents = divToPrint.innerHTML; - const originalContents = document.body.innerHTML; // Store original body content - - // Temporarily replace the body content with the div's content - document.body.innerHTML = printContents; - - // Trigger the print dialog - window.print(); - - // Restore the original body content - document.body.innerHTML = originalContents; + validateProjectURL(input: ResumeProject){ + let result = this.validator.validateURL(input.url); + input.url = result[1]; } addExperience(){ diff --git a/src/Client/src/app/services/Validation.ts b/src/Client/src/app/services/Validation.ts index 56314ea..ef7c99a 100644 --- a/src/Client/src/app/services/Validation.ts +++ b/src/Client/src/app/services/Validation.ts @@ -25,11 +25,65 @@ export class Validation { } } - emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; + emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; validateEmail(input: string): [boolean, string] { - const corrected = input.trim().toLowerCase(); + const trimmed = input.trim(); + const [local, domain] = trimmed.split('@'); + const corrected = domain ? `${local}@${domain.toLowerCase()}` : trimmed; + + // Extra checks to avoid invalid formats + if ( corrected.includes('..') || corrected.startsWith('.') || corrected.endsWith('.') ) { + return [false, corrected]; + } + const success = this.emailRegex.test(corrected); return [success, corrected]; } + validateURL(input: string): [boolean, string] { + const testUrl = /^https?:\/\//i.test(input) ? input : "http://" + input; + var urlToParse = new URL(testUrl); + try { + + if (urlToParse.protocol !== 'http:' && urlToParse.protocol !== 'https:') { + return [false, urlToParse.href]; + } + + const hostname = urlToParse.hostname.toLowerCase(); + if (hostname === 'localhost' || hostname.endsWith('.localhost')) { + return [false, urlToParse.href]; + } + + const privateIpRegex = /^(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)/; + if (privateIpRegex.test(hostname)) { + return [false, urlToParse.href]; + } + + if (hostname.includes(':')) { + if (this.isPrivateIPv6(hostname)) { + return [false, urlToParse.href]; + } + } + + return [true, urlToParse.href.substring(0, urlToParse.href.length - 1)]; + } catch (e) { + return [false, urlToParse.href]; + } + } + + ///////// HELPER FUNCTIONS ///////// + + isPrivateIPv6(ip: string): boolean { + try { + const normalized = ip.replace(/^\[|\]$/g, '').toLowerCase(); + if (normalized === '::1') return true; + if (normalized.startsWith('fc') || normalized.startsWith('fd')) return true; + const first4 = normalized.slice(0, 4); + if (first4 >= 'fe80' && first4 <= 'febf') return true; + return false; + } catch { + return true; + } +} + } \ No newline at end of file