@mikkelscheike/email-provider-links 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ /**
3
+ * Secure Loader for Email Providers
4
+ *
5
+ * Integrates URL validation and hash verification to create a secure
6
+ * loading system for email provider data.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.secureLoadProviders = secureLoadProviders;
10
+ exports.initializeSecurity = initializeSecurity;
11
+ exports.createSecurityMiddleware = createSecurityMiddleware;
12
+ const fs_1 = require("fs");
13
+ const path_1 = require("path");
14
+ const url_validator_1 = require("./url-validator");
15
+ const hash_verifier_1 = require("./hash-verifier");
16
+ /**
17
+ * Securely loads and validates email provider data
18
+ *
19
+ * @param providersPath - Path to the providers JSON file
20
+ * @param expectedHash - Optional expected hash for verification
21
+ * @returns Secure load result with validation details
22
+ */
23
+ function secureLoadProviders(providersPath, expectedHash) {
24
+ const filePath = providersPath || (0, path_1.join)(__dirname, '..', '..', 'providers', 'emailproviders.json');
25
+ const issues = [];
26
+ let providers = [];
27
+ // Step 1: Hash verification
28
+ const hashResult = (0, hash_verifier_1.verifyProvidersIntegrity)(filePath, expectedHash);
29
+ if (!hashResult.isValid) {
30
+ issues.push(`Hash verification failed: ${hashResult.reason}`);
31
+ // In production, you might want to abort here
32
+ console.error('🚨 SECURITY WARNING: Hash verification failed!');
33
+ console.error('File:', hashResult.file);
34
+ console.error('Reason:', hashResult.reason);
35
+ console.error('Expected:', hashResult.expectedHash);
36
+ console.error('Actual:', hashResult.actualHash);
37
+ }
38
+ // Step 2: Load and parse JSON
39
+ try {
40
+ const fileContent = (0, fs_1.readFileSync)(filePath, 'utf8');
41
+ const data = JSON.parse(fileContent);
42
+ providers = data.providers || [];
43
+ }
44
+ catch (error) {
45
+ issues.push(`Failed to load providers file: ${error instanceof Error ? error.message : 'Unknown error'}`);
46
+ return {
47
+ success: false,
48
+ providers: [],
49
+ securityReport: {
50
+ hashVerification: false,
51
+ urlValidation: false,
52
+ totalProviders: 0,
53
+ validUrls: 0,
54
+ invalidUrls: 0,
55
+ securityLevel: 'CRITICAL',
56
+ issues
57
+ }
58
+ };
59
+ }
60
+ // Step 3: URL validation audit
61
+ const urlAudit = (0, url_validator_1.auditProviderSecurity)(providers);
62
+ if (urlAudit.invalid > 0) {
63
+ issues.push(`${urlAudit.invalid} providers have invalid URLs`);
64
+ console.warn('āš ļø URL validation issues found:');
65
+ for (const invalid of urlAudit.invalidProviders) {
66
+ console.warn(`- ${invalid.provider}: ${invalid.validation.reason}`);
67
+ }
68
+ }
69
+ // Step 4: Filter out invalid providers in production
70
+ const secureProviders = providers.filter(provider => {
71
+ if (!provider.loginUrl)
72
+ return true; // Allow providers without login URLs
73
+ const validation = (0, url_validator_1.validateEmailProviderUrl)(provider.loginUrl);
74
+ return validation.isValid;
75
+ });
76
+ if (secureProviders.length < providers.length) {
77
+ const filtered = providers.length - secureProviders.length;
78
+ issues.push(`Filtered out ${filtered} providers with invalid URLs`);
79
+ }
80
+ // Step 5: Determine security level
81
+ let securityLevel = 'SECURE';
82
+ if (!hashResult.isValid) {
83
+ securityLevel = 'CRITICAL';
84
+ }
85
+ else if (urlAudit.invalid > 0 || issues.length > 0) {
86
+ securityLevel = 'WARNING';
87
+ }
88
+ return {
89
+ success: securityLevel !== 'CRITICAL',
90
+ providers: secureProviders,
91
+ securityReport: {
92
+ hashVerification: hashResult.isValid,
93
+ urlValidation: urlAudit.invalid === 0,
94
+ totalProviders: providers.length,
95
+ validUrls: urlAudit.valid,
96
+ invalidUrls: urlAudit.invalid,
97
+ securityLevel,
98
+ issues
99
+ }
100
+ };
101
+ }
102
+ /**
103
+ * Development utility to generate and display current hashes
104
+ */
105
+ function initializeSecurity() {
106
+ console.log('šŸ” Generating security hashes for email providers...');
107
+ const hashes = (0, hash_verifier_1.generateSecurityHashes)();
108
+ console.log('\nšŸ“‹ Security Setup Instructions:');
109
+ console.log('1. Store these hashes securely (environment variables, CI/CD secrets)');
110
+ console.log('2. Update KNOWN_GOOD_HASHES in hash-verifier.ts');
111
+ console.log('3. Enable hash verification in production');
112
+ console.log('\nāš ļø Remember to update hashes when making legitimate changes to provider data!');
113
+ return hashes;
114
+ }
115
+ /**
116
+ * Express middleware for secure provider loading (if using in web apps)
117
+ */
118
+ function createSecurityMiddleware(options = {}) {
119
+ return (req, res, next) => {
120
+ const result = secureLoadProviders(undefined, options.expectedHash);
121
+ if (result.securityReport.securityLevel === 'CRITICAL' && !options.allowInvalidUrls) {
122
+ if (options.onSecurityIssue) {
123
+ options.onSecurityIssue(result.securityReport);
124
+ }
125
+ return res.status(500).json({
126
+ error: 'Security validation failed',
127
+ details: result.securityReport
128
+ });
129
+ }
130
+ // Attach secure providers to request
131
+ req.secureProviders = result.providers;
132
+ req.securityReport = result.securityReport;
133
+ next();
134
+ };
135
+ }
136
+ exports.default = {
137
+ secureLoadProviders,
138
+ initializeSecurity,
139
+ createSecurityMiddleware
140
+ };
141
+ //# sourceMappingURL=secure-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-loader.js","sourceRoot":"","sources":["../../src/security/secure-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Security Demonstration Script
4
+ *
5
+ * This script demonstrates how the URL validation and hash verification
6
+ * systems work to protect against supply chain attacks.
7
+ */
8
+ declare function demo(): void;
9
+ export { demo };
10
+ //# sourceMappingURL=security-demo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-demo.d.ts","sourceRoot":"","sources":["../../src/security/security-demo.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAQH,iBAAS,IAAI,SA2JZ;AAOD,OAAO,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env tsx
2
+ "use strict";
3
+ /**
4
+ * Security Demonstration Script
5
+ *
6
+ * This script demonstrates how the URL validation and hash verification
7
+ * systems work to protect against supply chain attacks.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.demo = demo;
11
+ const url_validator_1 = require("./url-validator");
12
+ const hash_verifier_1 = require("./hash-verifier");
13
+ const secure_loader_1 = require("./secure-loader");
14
+ const fs_1 = require("fs");
15
+ const path_1 = require("path");
16
+ function demo() {
17
+ console.log('šŸ” EMAIL PROVIDER LINKS - SECURITY DEMONSTRATION\n');
18
+ // 1. URL Validation Demo
19
+ console.log('šŸ“‹ 1. URL VALIDATION DEMO');
20
+ console.log('='.repeat(50));
21
+ const testUrls = [
22
+ 'https://mail.google.com/mail/', // āœ… Valid
23
+ 'https://outlook.office365.com', // āœ… Valid
24
+ 'https://evil-phishing-site.com/gmail', // āŒ Invalid (not allowlisted)
25
+ 'http://gmail.com', // āŒ Invalid (not HTTPS)
26
+ 'https://192.168.1.1/webmail', // āŒ Invalid (IP address)
27
+ 'https://bit.ly/fake-gmail', // āŒ Invalid (URL shortener)
28
+ 'https://gmail.tk' // āŒ Invalid (suspicious TLD)
29
+ ];
30
+ testUrls.forEach(url => {
31
+ const result = (0, url_validator_1.validateEmailProviderUrl)(url);
32
+ const status = result.isValid ? 'āœ…' : 'āŒ';
33
+ console.log(`${status} ${url}`);
34
+ if (!result.isValid) {
35
+ console.log(` Reason: ${result.reason}`);
36
+ }
37
+ });
38
+ // 2. Hash Verification Demo
39
+ console.log('\nšŸ“‹ 2. HASH VERIFICATION DEMO');
40
+ console.log('='.repeat(50));
41
+ try {
42
+ const providersPath = (0, path_1.join)(__dirname, '..', '..', 'providers', 'emailproviders.json');
43
+ const currentHash = (0, hash_verifier_1.calculateFileHash)(providersPath);
44
+ console.log(`Current providers file hash: ${currentHash}`);
45
+ // Simulate tampering detection
46
+ const fakeHash = 'fake_hash_indicating_tampering';
47
+ const verificationResult = (0, hash_verifier_1.verifyProvidersIntegrity)(providersPath, fakeHash);
48
+ console.log(`\\nTampering simulation:`);
49
+ console.log(`Expected: ${fakeHash}`);
50
+ console.log(`Actual: ${verificationResult.actualHash}`);
51
+ console.log(`Valid: ${verificationResult.isValid ? 'āœ…' : 'āŒ'}`);
52
+ if (!verificationResult.isValid) {
53
+ console.log(`Reason: ${verificationResult.reason}`);
54
+ }
55
+ }
56
+ catch (error) {
57
+ console.error('Failed to demonstrate hash verification:', error);
58
+ }
59
+ // 3. Provider Security Audit
60
+ console.log('\\nšŸ“‹ 3. PROVIDER SECURITY AUDIT');
61
+ console.log('='.repeat(50));
62
+ try {
63
+ const providersPath = (0, path_1.join)(__dirname, '..', '..', 'providers', 'emailproviders.json');
64
+ const providersData = JSON.parse((0, fs_1.readFileSync)(providersPath, 'utf8'));
65
+ const audit = (0, url_validator_1.auditProviderSecurity)(providersData.providers);
66
+ console.log(`Total providers: ${audit.total}`);
67
+ console.log(`Valid URLs: ${audit.valid}`);
68
+ console.log(`Invalid URLs: ${audit.invalid}`);
69
+ console.log(`Status: ${audit.report}`);
70
+ if (audit.invalid > 0) {
71
+ console.log('\\nInvalid providers:');
72
+ audit.invalidProviders.forEach(invalid => {
73
+ console.log(`- ${invalid.provider}: ${invalid.validation.reason}`);
74
+ });
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.error('Failed to audit providers:', error);
79
+ }
80
+ // 4. Secure Loading Demo
81
+ console.log('\\nšŸ“‹ 4. SECURE LOADING DEMO');
82
+ console.log('='.repeat(50));
83
+ const secureResult = (0, secure_loader_1.secureLoadProviders)();
84
+ console.log(`Load success: ${secureResult.success ? 'āœ…' : 'āŒ'}`);
85
+ console.log(`Security level: ${secureResult.securityReport.securityLevel}`);
86
+ console.log(`Hash verification: ${secureResult.securityReport.hashVerification ? 'āœ…' : 'āŒ'}`);
87
+ console.log(`URL validation: ${secureResult.securityReport.urlValidation ? 'āœ…' : 'āŒ'}`);
88
+ console.log(`Total providers loaded: ${secureResult.providers.length}`);
89
+ if (secureResult.securityReport.issues.length > 0) {
90
+ console.log('\\nSecurity issues:');
91
+ secureResult.securityReport.issues.forEach(issue => {
92
+ console.log(`- ${issue}`);
93
+ });
94
+ }
95
+ // 5. Attack Simulation
96
+ console.log('\\nšŸ“‹ 5. ATTACK SIMULATION');
97
+ console.log('='.repeat(50));
98
+ console.log('Simulating common attack scenarios:\\n');
99
+ // Simulate malicious URL injection
100
+ const maliciousProvider = {
101
+ companyProvider: 'Fake Gmail',
102
+ loginUrl: 'https://gmaiI.com/login', // Note the capital i instead of l
103
+ domains: ['gmail.com']
104
+ };
105
+ const maliciousValidation = (0, url_validator_1.validateEmailProviderUrl)(maliciousProvider.loginUrl);
106
+ console.log(`šŸŽ­ Typosquatting attack: ${maliciousProvider.loginUrl}`);
107
+ console.log(` Blocked: ${!maliciousValidation.isValid ? 'āœ…' : 'āŒ'}`);
108
+ if (!maliciousValidation.isValid) {
109
+ console.log(` Reason: ${maliciousValidation.reason}`);
110
+ }
111
+ // Simulate URL shortener attack
112
+ const shortenerAttack = {
113
+ companyProvider: 'Shortened Gmail',
114
+ loginUrl: 'https://bit.ly/definitely-not-gmail',
115
+ domains: ['gmail.com']
116
+ };
117
+ const shortenerValidation = (0, url_validator_1.validateEmailProviderUrl)(shortenerAttack.loginUrl);
118
+ console.log(`\\nšŸ”— URL shortener attack: ${shortenerAttack.loginUrl}`);
119
+ console.log(` Blocked: ${!shortenerValidation.isValid ? 'āœ…' : 'āŒ'}`);
120
+ if (!shortenerValidation.isValid) {
121
+ console.log(` Reason: ${shortenerValidation.reason}`);
122
+ }
123
+ // Simulate non-HTTPS attack
124
+ const httpAttack = {
125
+ companyProvider: 'Insecure Gmail',
126
+ loginUrl: 'http://gmail.com',
127
+ domains: ['gmail.com']
128
+ };
129
+ const httpValidation = (0, url_validator_1.validateEmailProviderUrl)(httpAttack.loginUrl);
130
+ console.log(`\\nšŸ”“ Non-HTTPS attack: ${httpAttack.loginUrl}`);
131
+ console.log(` Blocked: ${!httpValidation.isValid ? 'āœ…' : 'āŒ'}`);
132
+ if (!httpValidation.isValid) {
133
+ console.log(` Reason: ${httpValidation.reason}`);
134
+ }
135
+ console.log('\\nšŸŽÆ SECURITY SUMMARY');
136
+ console.log('='.repeat(50));
137
+ console.log('āœ… URL allowlisting prevents malicious redirects');
138
+ console.log('āœ… Hash verification detects file tampering');
139
+ console.log('āœ… HTTPS enforcement prevents downgrade attacks');
140
+ console.log('āœ… Suspicious pattern detection blocks common attacks');
141
+ console.log('āœ… Comprehensive logging for security monitoring');
142
+ console.log('\\nšŸ”§ NEXT STEPS FOR PRODUCTION');
143
+ console.log('='.repeat(50));
144
+ console.log('1. Store expected hashes in environment variables');
145
+ console.log('2. Enable strict security mode in CI/CD pipeline');
146
+ console.log('3. Set up monitoring alerts for security failures');
147
+ console.log('4. Regular security audits of provider data');
148
+ console.log('5. Consider adding digital signatures for extra security');
149
+ }
150
+ // Run the demo
151
+ if (require.main === module) {
152
+ demo();
153
+ }
154
+ //# sourceMappingURL=security-demo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security-demo.js","sourceRoot":"","sources":["../../src/security/security-demo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * URL Security Validation Module
3
+ *
4
+ * Provides validation and allowlisting for email provider URLs to prevent
5
+ * malicious redirects and supply chain attacks.
6
+ */
7
+ export interface URLValidationResult {
8
+ isValid: boolean;
9
+ reason?: string;
10
+ domain?: string;
11
+ normalizedUrl?: string;
12
+ }
13
+ /**
14
+ * Validates if a URL is safe for email provider redirects
15
+ *
16
+ * @param url - The URL to validate
17
+ * @returns Validation result with details
18
+ */
19
+ export declare function validateEmailProviderUrl(url: string): URLValidationResult;
20
+ /**
21
+ * Validates all URLs in an email providers array
22
+ *
23
+ * @param providers - Array of email providers to validate
24
+ * @returns Array of validation results
25
+ */
26
+ export declare function validateAllProviderUrls(providers: any[]): Array<{
27
+ provider: string;
28
+ url: string;
29
+ validation: URLValidationResult;
30
+ }>;
31
+ /**
32
+ * Security audit function to check all provider URLs
33
+ *
34
+ * @param providers - Array of email providers to audit
35
+ * @returns Security audit report
36
+ */
37
+ export declare function auditProviderSecurity(providers: any[]): {
38
+ total: number;
39
+ valid: number;
40
+ invalid: number;
41
+ invalidProviders: {
42
+ provider: string;
43
+ url: string;
44
+ validation: URLValidationResult;
45
+ }[];
46
+ report: string;
47
+ };
48
+ //# sourceMappingURL=url-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/security/url-validator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwIH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CA4HzE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,mBAAmB,CAAC;CACjC,CAAC,CAkBD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,GAAG,EAAE;;;;;kBA7B1C,MAAM;aACX,MAAM;oBACC,mBAAmB;;;EAyChC"}
@@ -0,0 +1,294 @@
1
+ "use strict";
2
+ /**
3
+ * URL Security Validation Module
4
+ *
5
+ * Provides validation and allowlisting for email provider URLs to prevent
6
+ * malicious redirects and supply chain attacks.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.validateEmailProviderUrl = validateEmailProviderUrl;
10
+ exports.validateAllProviderUrls = validateAllProviderUrls;
11
+ exports.auditProviderSecurity = auditProviderSecurity;
12
+ /**
13
+ * Allowlisted domains for email providers.
14
+ * Only URLs from these domains will be considered safe.
15
+ *
16
+ * NOTE: This list should be maintained carefully and updated only
17
+ * through security review processes.
18
+ */
19
+ const ALLOWED_DOMAINS = [
20
+ // Google services
21
+ 'google.com',
22
+ 'gmail.com',
23
+ 'googlemail.com',
24
+ 'mail.google.com',
25
+ 'accounts.google.com',
26
+ // Microsoft services
27
+ 'microsoft.com',
28
+ 'outlook.com',
29
+ 'outlook.office365.com',
30
+ 'hotmail.com',
31
+ 'live.com',
32
+ 'office.com',
33
+ // Yahoo services
34
+ 'yahoo.com',
35
+ 'yahoo.co.uk',
36
+ 'yahoo.fr',
37
+ 'yahoo.de',
38
+ 'login.yahoo.com',
39
+ // Privacy-focused providers
40
+ 'proton.me',
41
+ 'protonmail.com',
42
+ 'protonmail.ch',
43
+ 'tutanota.com',
44
+ 'tutanota.de',
45
+ 'posteo.de',
46
+ 'runbox.com',
47
+ 'countermail.com',
48
+ 'hushmail.com',
49
+ // Business providers
50
+ 'zoho.com',
51
+ 'fastmail.com',
52
+ 'rackspace.com',
53
+ 'apps.rackspace.com',
54
+ // Other legitimate providers
55
+ 'aol.com',
56
+ 'mail.aol.com',
57
+ 'gmx.com',
58
+ 'gmx.net',
59
+ 'mail.com',
60
+ 'yandex.com',
61
+ 'yandex.ru',
62
+ 'web.de',
63
+ 'mail.ru',
64
+ 'libero.it',
65
+ 'orange.fr',
66
+ 'free.fr',
67
+ 't-online.de',
68
+ 'comcast.net',
69
+ 'att.net',
70
+ 'verizon.net',
71
+ 'bluehost.com',
72
+ 'godaddy.com',
73
+ 'secureserver.net',
74
+ // Additional providers from security audit
75
+ 'kolabnow.com',
76
+ 'connect.xfinity.com',
77
+ 'login.verizon.com',
78
+ 'www.simply.com',
79
+ 'www.one.com',
80
+ 'mailfence.com',
81
+ 'neo.space',
82
+ 'mail.126.com',
83
+ 'mail.qq.com',
84
+ 'mail.sina.com.cn',
85
+ 'www.xtra.co.nz',
86
+ 'mail.rediff.com',
87
+ 'mail.rakuten.co.jp',
88
+ 'mail.nifty.com',
89
+ 'mail.iij.ad.jp',
90
+ 'email.uol.com.br',
91
+ 'email.bol.com.br',
92
+ 'email.globo.com',
93
+ 'webmail.terra.com.br',
94
+ 'webmail.movistar.es',
95
+ 'webmail.ono.com',
96
+ 'webmail.telkom.co.za',
97
+ 'webmail.vodacom.co.za',
98
+ 'webmail.mtnonline.com',
99
+ 'bdmail.net',
100
+ 'mail.aamra.com.bd',
101
+ 'mail.link3.net',
102
+ 'mail.ionos.com',
103
+ 'www.icloud.com',
104
+ 'icloud.com',
105
+ 'mail.hostinger.com',
106
+ 'ngx257.inmotionhosting.com',
107
+ 'privateemail.com',
108
+ 'app.titan.email',
109
+ 'tools.siteground.com',
110
+ 'portal.hostgator.com'
111
+ ];
112
+ /**
113
+ * Suspicious URL patterns that should always be rejected
114
+ */
115
+ const SUSPICIOUS_PATTERNS = [
116
+ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/, // IP addresses
117
+ /localhost/i,
118
+ /127\.0\.0\.1/,
119
+ /192\.168\./,
120
+ /10\./,
121
+ /172\./,
122
+ /\.tk$|\.ml$|\.ga$|\.cf$/i, // Suspicious TLDs
123
+ /[a-z0-9]+-[a-z0-9]+-[a-z0-9]+\./i, // Random subdomain patterns
124
+ ];
125
+ /**
126
+ * URL shortener domains (should be rejected for security)
127
+ */
128
+ const URL_SHORTENERS = [
129
+ 'bit.ly',
130
+ 'tinyurl.com',
131
+ 't.co',
132
+ 'short.link',
133
+ 'ow.ly',
134
+ 'is.gd',
135
+ 'buff.ly'
136
+ ];
137
+ /**
138
+ * Validates if a URL is safe for email provider redirects
139
+ *
140
+ * @param url - The URL to validate
141
+ * @returns Validation result with details
142
+ */
143
+ function validateEmailProviderUrl(url) {
144
+ try {
145
+ // Check for malicious patterns in raw URL before parsing
146
+ const rawUrl = url.toLowerCase();
147
+ // Decode URL to catch encoded malicious patterns
148
+ let decodedUrl = '';
149
+ try {
150
+ decodedUrl = decodeURIComponent(rawUrl);
151
+ }
152
+ catch {
153
+ // If URL can't be decoded, treat as suspicious
154
+ return {
155
+ isValid: false,
156
+ reason: 'URL contains potentially malicious content',
157
+ domain: 'unknown'
158
+ };
159
+ }
160
+ // Check both raw and decoded URLs for malicious patterns
161
+ const urlsToCheck = [rawUrl, decodedUrl];
162
+ for (const urlToCheck of urlsToCheck) {
163
+ if (urlToCheck.includes('..') ||
164
+ urlToCheck.includes('%2e%2e') ||
165
+ urlToCheck.includes('javascript:') ||
166
+ urlToCheck.includes('data:') ||
167
+ urlToCheck.includes('vbscript:') ||
168
+ urlToCheck.includes('file:') ||
169
+ urlToCheck.includes('about:') ||
170
+ urlToCheck.includes('<script') ||
171
+ urlToCheck.includes('onload=') ||
172
+ urlToCheck.includes('onerror=')) {
173
+ return {
174
+ isValid: false,
175
+ reason: 'URL contains potentially malicious content',
176
+ domain: 'unknown'
177
+ };
178
+ }
179
+ }
180
+ // Parse and normalize the URL
181
+ const urlObj = new URL(url);
182
+ const domain = urlObj.hostname.toLowerCase();
183
+ const normalizedUrl = urlObj.toString();
184
+ // Must use HTTPS
185
+ if (urlObj.protocol !== 'https:') {
186
+ return {
187
+ isValid: false,
188
+ reason: 'URL must use HTTPS protocol',
189
+ domain
190
+ };
191
+ }
192
+ // Check for suspicious patterns
193
+ for (const pattern of SUSPICIOUS_PATTERNS) {
194
+ if (pattern.test(domain)) {
195
+ return {
196
+ isValid: false,
197
+ reason: 'URL contains suspicious patterns',
198
+ domain
199
+ };
200
+ }
201
+ }
202
+ // Check for URL shorteners
203
+ if (URL_SHORTENERS.includes(domain)) {
204
+ return {
205
+ isValid: false,
206
+ reason: 'URL shorteners are not allowed',
207
+ domain
208
+ };
209
+ }
210
+ // Check against allowlist
211
+ const isAllowed = ALLOWED_DOMAINS.some(allowedDomain => {
212
+ // Exact match or subdomain match
213
+ return domain === allowedDomain || domain.endsWith(`.${allowedDomain}`);
214
+ });
215
+ if (!isAllowed) {
216
+ return {
217
+ isValid: false,
218
+ reason: `Domain '${domain}' is not in the allowlist`,
219
+ domain
220
+ };
221
+ }
222
+ // Additional security checks for malicious content
223
+ const fullUrl = urlObj.toString().toLowerCase();
224
+ const pathname = urlObj.pathname.toLowerCase();
225
+ const search = urlObj.search.toLowerCase();
226
+ // Check for path traversal
227
+ if (pathname.includes('..') || pathname.includes('%2e%2e')) {
228
+ return {
229
+ isValid: false,
230
+ reason: 'URL contains potentially malicious content',
231
+ domain
232
+ };
233
+ }
234
+ // Check for JavaScript injection
235
+ if (fullUrl.includes('javascript:') || search.includes('javascript') || fullUrl.includes('data:')) {
236
+ return {
237
+ isValid: false,
238
+ reason: 'URL contains potentially malicious content',
239
+ domain
240
+ };
241
+ }
242
+ return {
243
+ isValid: true,
244
+ domain,
245
+ normalizedUrl
246
+ };
247
+ }
248
+ catch (error) {
249
+ return {
250
+ isValid: false,
251
+ reason: `Invalid URL format: ${error instanceof Error ? error.message : 'Unknown error'}`
252
+ };
253
+ }
254
+ }
255
+ /**
256
+ * Validates all URLs in an email providers array
257
+ *
258
+ * @param providers - Array of email providers to validate
259
+ * @returns Array of validation results
260
+ */
261
+ function validateAllProviderUrls(providers) {
262
+ const results = [];
263
+ for (const provider of providers) {
264
+ if (provider.loginUrl) {
265
+ results.push({
266
+ provider: provider.companyProvider || 'Unknown',
267
+ url: provider.loginUrl,
268
+ validation: validateEmailProviderUrl(provider.loginUrl)
269
+ });
270
+ }
271
+ }
272
+ return results;
273
+ }
274
+ /**
275
+ * Security audit function to check all provider URLs
276
+ *
277
+ * @param providers - Array of email providers to audit
278
+ * @returns Security audit report
279
+ */
280
+ function auditProviderSecurity(providers) {
281
+ const validations = validateAllProviderUrls(providers);
282
+ const invalid = validations.filter(v => !v.validation.isValid);
283
+ const valid = validations.filter(v => v.validation.isValid);
284
+ return {
285
+ total: validations.length,
286
+ valid: valid.length,
287
+ invalid: invalid.length,
288
+ invalidProviders: invalid,
289
+ report: invalid.length === 0
290
+ ? 'āœ… All provider URLs passed security validation'
291
+ : `āš ļø ${invalid.length} provider(s) failed security validation`
292
+ };
293
+ }
294
+ //# sourceMappingURL=url-validator.js.map