@mikkelscheike/email-provider-links 1.1.0 โ 1.3.1
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.
- package/README.md +61 -7
- package/dist/security/hash-verifier.d.ts +94 -0
- package/dist/security/hash-verifier.d.ts.map +1 -0
- package/dist/security/hash-verifier.js +284 -0
- package/dist/security/hash-verifier.js.map +1 -0
- package/dist/security/secure-loader.d.ts +47 -0
- package/dist/security/secure-loader.d.ts.map +1 -0
- package/dist/security/secure-loader.js +141 -0
- package/dist/security/secure-loader.js.map +1 -0
- package/dist/security/security-demo.d.ts +10 -0
- package/dist/security/security-demo.d.ts.map +1 -0
- package/dist/security/security-demo.js +154 -0
- package/dist/security/security-demo.js.map +1 -0
- package/dist/security/url-validator.d.ts +48 -0
- package/dist/security/url-validator.d.ts.map +1 -0
- package/dist/security/url-validator.js +294 -0
- package/dist/security/url-validator.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# Email Provider Links
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
๐ **Enterprise-grade secure email provider detection for login and password reset flows**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A TypeScript package that provides direct links to email providers based on email addresses, with comprehensive security features to prevent malicious redirects and supply chain attacks.
|
|
6
|
+
|
|
7
|
+
## โจ Features
|
|
6
8
|
|
|
7
9
|
- ๐ **Fast & Lightweight**: Zero dependencies, minimal footprint
|
|
8
|
-
- ๐ง **
|
|
9
|
-
- ๐ข **Business Domain Detection**: DNS-based detection for custom domains
|
|
10
|
-
- ๐ **
|
|
10
|
+
- ๐ง **64+ Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and more
|
|
11
|
+
- ๐ข **Business Domain Detection**: DNS-based detection for custom domains (Google Workspace, Microsoft 365, etc.)
|
|
12
|
+
- ๐ **Enterprise Security**: Multi-layer protection against malicious URLs and supply chain attacks
|
|
13
|
+
- ๐ก๏ธ **URL Validation**: HTTPS-only enforcement with domain allowlisting
|
|
14
|
+
- ๐ **Integrity Verification**: Cryptographic hash verification for data integrity
|
|
15
|
+
- ๐ **Type Safe**: Full TypeScript support with comprehensive interfaces
|
|
11
16
|
- โก **Performance Optimized**: Smart DNS fallback with configurable timeouts
|
|
17
|
+
- ๐งช **Thoroughly Tested**: 83+ tests including comprehensive security coverage
|
|
12
18
|
|
|
13
19
|
## Installation
|
|
14
20
|
|
|
@@ -93,13 +99,61 @@ interface EmailProviderResult {
|
|
|
93
99
|
}
|
|
94
100
|
```
|
|
95
101
|
|
|
102
|
+
## ๐ก๏ธ Security Features
|
|
103
|
+
|
|
104
|
+
This package implements **enterprise-grade security** to protect against malicious redirects and supply chain attacks:
|
|
105
|
+
|
|
106
|
+
### โ
Multi-Layer Protection
|
|
107
|
+
|
|
108
|
+
- **HTTPS-Only Enforcement**: All provider URLs must use HTTPS protocol
|
|
109
|
+
- **Domain Allowlisting**: Only pre-approved domains are allowed (64+ verified providers)
|
|
110
|
+
- **Malicious Pattern Detection**: Blocks IP addresses, URL shorteners, suspicious TLDs
|
|
111
|
+
- **Path Traversal Prevention**: Detects and blocks `../` and encoded variants
|
|
112
|
+
- **JavaScript Injection Protection**: Prevents `javascript:`, `data:`, and script injections
|
|
113
|
+
- **File Integrity Verification**: SHA-256 hash verification for provider database
|
|
114
|
+
|
|
115
|
+
### ๐ Attack Prevention
|
|
116
|
+
|
|
117
|
+
Protects against common attack vectors:
|
|
118
|
+
- โ **URL Injection**: Blocked by strict allowlisting
|
|
119
|
+
- โ **Typosquatting**: Blocked by domain validation
|
|
120
|
+
- โ **URL Shorteners**: Blocked by pattern detection
|
|
121
|
+
- โ **Protocol Downgrade**: Blocked by HTTPS enforcement
|
|
122
|
+
- โ **Path Traversal**: Blocked by path validation
|
|
123
|
+
- โ **Script Injection**: Blocked by content validation
|
|
124
|
+
- โ **Supply Chain Attacks**: Blocked by integrity verification
|
|
125
|
+
|
|
126
|
+
### ๐งช Security Testing
|
|
127
|
+
|
|
128
|
+
- **29 dedicated security tests** covering all attack vectors
|
|
129
|
+
- **94% security code coverage** with edge case testing
|
|
130
|
+
- **Automated security validation** in CI/CD pipeline
|
|
131
|
+
- **Regular security audits** of provider database
|
|
132
|
+
|
|
133
|
+
### ๐ For Security Teams
|
|
134
|
+
|
|
135
|
+
Security validation can be integrated into your workflow:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { secureLoadProviders } from '@mikkelscheike/email-provider-links/security';
|
|
139
|
+
|
|
140
|
+
// Secure loading with integrity verification
|
|
141
|
+
const result = secureLoadProviders();
|
|
142
|
+
if (result.securityReport.securityLevel === 'CRITICAL') {
|
|
143
|
+
// Handle security incident
|
|
144
|
+
console.error('Security validation failed:', result.securityReport.issues);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
96
148
|
## Contributing
|
|
97
149
|
|
|
98
|
-
We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding new email providers.
|
|
150
|
+
We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
|
|
151
|
+
|
|
152
|
+
**Security Note**: All new providers undergo security validation and must pass our allowlist verification.
|
|
99
153
|
|
|
100
154
|
## Security
|
|
101
155
|
|
|
102
|
-
For security concerns, see our [Security Policy](SECURITY.md).
|
|
156
|
+
For security concerns or to report vulnerabilities, see our [Security Policy](docs/SECURITY.md).
|
|
103
157
|
|
|
104
158
|
## License
|
|
105
159
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash Verification System
|
|
3
|
+
*
|
|
4
|
+
* Provides cryptographic integrity verification for the email providers database
|
|
5
|
+
* to detect tampering or unauthorized modifications.
|
|
6
|
+
*/
|
|
7
|
+
export interface HashVerificationResult {
|
|
8
|
+
isValid: boolean;
|
|
9
|
+
expectedHash?: string;
|
|
10
|
+
actualHash: string;
|
|
11
|
+
reason?: string;
|
|
12
|
+
file: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Calculates SHA-256 hash of a file or string content
|
|
16
|
+
*
|
|
17
|
+
* @param content - File content as string or Buffer
|
|
18
|
+
* @returns SHA-256 hash as hex string
|
|
19
|
+
*/
|
|
20
|
+
export declare function calculateHash(content: string | Buffer): string;
|
|
21
|
+
/**
|
|
22
|
+
* Calculates SHA-256 hash of a file
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - Path to the file
|
|
25
|
+
* @returns SHA-256 hash as hex string
|
|
26
|
+
*/
|
|
27
|
+
export declare function calculateFileHash(filePath: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Verifies the integrity of the email providers JSON file
|
|
30
|
+
*
|
|
31
|
+
* @param filePath - Path to the providers JSON file
|
|
32
|
+
* @param expectedHash - Optional expected hash (if not provided, uses KNOWN_GOOD_HASHES)
|
|
33
|
+
* @returns Verification result
|
|
34
|
+
*/
|
|
35
|
+
export declare function verifyProvidersIntegrity(filePath: string, expectedHash?: string): HashVerificationResult;
|
|
36
|
+
/**
|
|
37
|
+
* Verifies the integrity of providers data from JSON object
|
|
38
|
+
*
|
|
39
|
+
* @param providersData - The providers data object
|
|
40
|
+
* @param expectedHash - Expected hash of the JSON string
|
|
41
|
+
* @returns Verification result
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyProvidersDataIntegrity(providersData: any, expectedHash?: string): HashVerificationResult;
|
|
44
|
+
/**
|
|
45
|
+
* Generates security hashes for critical files - use this during development
|
|
46
|
+
*
|
|
47
|
+
* @param basePath - Base path of the project
|
|
48
|
+
* @returns Object with calculated hashes
|
|
49
|
+
*/
|
|
50
|
+
export declare function generateSecurityHashes(basePath?: string): Record<string, string>;
|
|
51
|
+
/**
|
|
52
|
+
* Easy-to-use function to recalculate and display current hashes
|
|
53
|
+
* for updating KNOWN_GOOD_HASHES when making legitimate changes
|
|
54
|
+
*
|
|
55
|
+
* @param basePath - Base path of the project
|
|
56
|
+
* @returns Formatted hash configuration for copy-paste
|
|
57
|
+
*/
|
|
58
|
+
export declare function recalculateHashes(basePath?: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Enhanced security warning system for hash mismatches
|
|
61
|
+
*
|
|
62
|
+
* @param result - Hash verification result
|
|
63
|
+
* @param options - Warning options
|
|
64
|
+
*/
|
|
65
|
+
export declare function handleHashMismatch(result: HashVerificationResult, options?: {
|
|
66
|
+
throwOnMismatch?: boolean;
|
|
67
|
+
logLevel?: 'error' | 'warn' | 'silent';
|
|
68
|
+
onMismatch?: (result: HashVerificationResult) => void;
|
|
69
|
+
}): void;
|
|
70
|
+
/**
|
|
71
|
+
* Comprehensive security audit including hash verification
|
|
72
|
+
*
|
|
73
|
+
* @param providersFilePath - Path to providers JSON file
|
|
74
|
+
* @returns Complete security audit result
|
|
75
|
+
*/
|
|
76
|
+
export declare function performSecurityAudit(providersFilePath?: string): {
|
|
77
|
+
hashVerification: HashVerificationResult;
|
|
78
|
+
recommendations: string[];
|
|
79
|
+
securityLevel: 'HIGH' | 'MEDIUM' | 'LOW' | 'CRITICAL';
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Creates a signed manifest of all provider URLs with their hashes
|
|
83
|
+
* This can be used to detect any URL modifications
|
|
84
|
+
*
|
|
85
|
+
* @param providers - Array of email providers
|
|
86
|
+
* @returns Signed manifest with URL hashes
|
|
87
|
+
*/
|
|
88
|
+
export declare function createProviderManifest(providers: any[]): {
|
|
89
|
+
timestamp: string;
|
|
90
|
+
providerCount: number;
|
|
91
|
+
urlHashes: Record<string, string>;
|
|
92
|
+
manifestHash: string;
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=hash-verifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-verifier.d.ts","sourceRoot":"","sources":["../../src/security/hash-verifier.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqBH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,sBAAsB,CAgCxB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,aAAa,EAAE,GAAG,EAClB,YAAY,CAAC,EAAE,MAAM,GACpB,sBAAsB,CAmCxB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,GAAE,MAAkB,0BAoBlE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAuB3D;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,GAAE;IACP,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CAClD,GACL,IAAI,CA6CN;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG;IAChE,gBAAgB,EAAE,sBAAsB,CAAC;IACzC,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,UAAU,CAAC;CACvD,CA6BA;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB,CAsBA"}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hash Verification System
|
|
4
|
+
*
|
|
5
|
+
* Provides cryptographic integrity verification for the email providers database
|
|
6
|
+
* to detect tampering or unauthorized modifications.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.calculateHash = calculateHash;
|
|
10
|
+
exports.calculateFileHash = calculateFileHash;
|
|
11
|
+
exports.verifyProvidersIntegrity = verifyProvidersIntegrity;
|
|
12
|
+
exports.verifyProvidersDataIntegrity = verifyProvidersDataIntegrity;
|
|
13
|
+
exports.generateSecurityHashes = generateSecurityHashes;
|
|
14
|
+
exports.recalculateHashes = recalculateHashes;
|
|
15
|
+
exports.handleHashMismatch = handleHashMismatch;
|
|
16
|
+
exports.performSecurityAudit = performSecurityAudit;
|
|
17
|
+
exports.createProviderManifest = createProviderManifest;
|
|
18
|
+
const crypto_1 = require("crypto");
|
|
19
|
+
const fs_1 = require("fs");
|
|
20
|
+
const path_1 = require("path");
|
|
21
|
+
/**
|
|
22
|
+
* Known good hashes for the providers database.
|
|
23
|
+
* These should be updated whenever the legitimate data changes.
|
|
24
|
+
*
|
|
25
|
+
* IMPORTANT: These hashes should be stored in a separate, more secure location
|
|
26
|
+
* in production (e.g., environment variables, secure CI/CD secrets)
|
|
27
|
+
*/
|
|
28
|
+
const KNOWN_GOOD_HASHES = {
|
|
29
|
+
// SHA-256 hash of the legitimate emailproviders.json
|
|
30
|
+
'emailproviders.json': 'da7a856fe04b11e326230d195fcc3d44f078e481b8929cf4fb5040276e05ffd0',
|
|
31
|
+
// You can add hashes for other critical files
|
|
32
|
+
'package.json': '4fec42bf25d33615a2b19bfe573b6d706404d39bfcdd6464a6958e70fca2a579'
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Calculates SHA-256 hash of a file or string content
|
|
36
|
+
*
|
|
37
|
+
* @param content - File content as string or Buffer
|
|
38
|
+
* @returns SHA-256 hash as hex string
|
|
39
|
+
*/
|
|
40
|
+
function calculateHash(content) {
|
|
41
|
+
return (0, crypto_1.createHash)('sha256').update(content).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Calculates SHA-256 hash of a file
|
|
45
|
+
*
|
|
46
|
+
* @param filePath - Path to the file
|
|
47
|
+
* @returns SHA-256 hash as hex string
|
|
48
|
+
*/
|
|
49
|
+
function calculateFileHash(filePath) {
|
|
50
|
+
const content = (0, fs_1.readFileSync)(filePath);
|
|
51
|
+
return calculateHash(content);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Verifies the integrity of the email providers JSON file
|
|
55
|
+
*
|
|
56
|
+
* @param filePath - Path to the providers JSON file
|
|
57
|
+
* @param expectedHash - Optional expected hash (if not provided, uses KNOWN_GOOD_HASHES)
|
|
58
|
+
* @returns Verification result
|
|
59
|
+
*/
|
|
60
|
+
function verifyProvidersIntegrity(filePath, expectedHash) {
|
|
61
|
+
try {
|
|
62
|
+
const actualHash = calculateFileHash(filePath);
|
|
63
|
+
const expectedHashToUse = expectedHash || KNOWN_GOOD_HASHES['emailproviders.json'];
|
|
64
|
+
if (expectedHashToUse === 'TO_BE_CALCULATED') {
|
|
65
|
+
return {
|
|
66
|
+
isValid: false,
|
|
67
|
+
actualHash,
|
|
68
|
+
reason: 'Expected hash not configured. Run generateSecurityHashes() first.',
|
|
69
|
+
file: filePath
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const isValid = actualHash === expectedHashToUse;
|
|
73
|
+
return {
|
|
74
|
+
isValid,
|
|
75
|
+
expectedHash: expectedHashToUse,
|
|
76
|
+
actualHash,
|
|
77
|
+
reason: isValid ? undefined : 'File hash does not match expected value - potential tampering detected',
|
|
78
|
+
file: filePath
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
isValid: false,
|
|
84
|
+
actualHash: '',
|
|
85
|
+
reason: `Failed to verify file: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
86
|
+
file: filePath
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Verifies the integrity of providers data from JSON object
|
|
92
|
+
*
|
|
93
|
+
* @param providersData - The providers data object
|
|
94
|
+
* @param expectedHash - Expected hash of the JSON string
|
|
95
|
+
* @returns Verification result
|
|
96
|
+
*/
|
|
97
|
+
function verifyProvidersDataIntegrity(providersData, expectedHash) {
|
|
98
|
+
try {
|
|
99
|
+
// Create deterministic JSON string (sorted keys)
|
|
100
|
+
const jsonString = JSON.stringify(providersData, Object.keys(providersData).sort(), 2);
|
|
101
|
+
const actualHash = calculateHash(jsonString);
|
|
102
|
+
const expectedHashToUse = expectedHash || KNOWN_GOOD_HASHES['emailproviders.json'];
|
|
103
|
+
if (expectedHashToUse === 'TO_BE_CALCULATED') {
|
|
104
|
+
return {
|
|
105
|
+
isValid: false,
|
|
106
|
+
actualHash,
|
|
107
|
+
reason: 'Expected hash not configured',
|
|
108
|
+
file: 'providersData'
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const isValid = actualHash === expectedHashToUse;
|
|
112
|
+
return {
|
|
113
|
+
isValid,
|
|
114
|
+
expectedHash: expectedHashToUse,
|
|
115
|
+
actualHash,
|
|
116
|
+
reason: isValid ? undefined : 'Data hash does not match expected value',
|
|
117
|
+
file: 'providersData'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
isValid: false,
|
|
123
|
+
actualHash: '',
|
|
124
|
+
reason: `Failed to verify data: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
125
|
+
file: 'providersData'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Generates security hashes for critical files - use this during development
|
|
131
|
+
*
|
|
132
|
+
* @param basePath - Base path of the project
|
|
133
|
+
* @returns Object with calculated hashes
|
|
134
|
+
*/
|
|
135
|
+
function generateSecurityHashes(basePath = __dirname) {
|
|
136
|
+
const files = [
|
|
137
|
+
'providers/emailproviders.json',
|
|
138
|
+
'package.json'
|
|
139
|
+
];
|
|
140
|
+
const hashes = {};
|
|
141
|
+
for (const file of files) {
|
|
142
|
+
try {
|
|
143
|
+
const fullPath = (0, path_1.join)(basePath, '..', '..', file);
|
|
144
|
+
const hash = calculateFileHash(fullPath);
|
|
145
|
+
hashes[file.split('/').pop() || file] = hash;
|
|
146
|
+
console.log(`โ
${file}: ${hash}`);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error(`โ Failed to hash ${file}:`, error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return hashes;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Easy-to-use function to recalculate and display current hashes
|
|
156
|
+
* for updating KNOWN_GOOD_HASHES when making legitimate changes
|
|
157
|
+
*
|
|
158
|
+
* @param basePath - Base path of the project
|
|
159
|
+
* @returns Formatted hash configuration for copy-paste
|
|
160
|
+
*/
|
|
161
|
+
function recalculateHashes(basePath) {
|
|
162
|
+
console.log('๐ RECALCULATING SECURITY HASHES');
|
|
163
|
+
console.log('='.repeat(50));
|
|
164
|
+
const hashes = generateSecurityHashes(basePath);
|
|
165
|
+
const configCode = `
|
|
166
|
+
// Updated KNOWN_GOOD_HASHES configuration:
|
|
167
|
+
const KNOWN_GOOD_HASHES = {
|
|
168
|
+
'emailproviders.json': '${hashes['emailproviders.json']}',
|
|
169
|
+
'package.json': '${hashes['package.json']}'
|
|
170
|
+
};
|
|
171
|
+
`;
|
|
172
|
+
console.log('\n๐ Copy this configuration to hash-verifier.ts:');
|
|
173
|
+
console.log(configCode);
|
|
174
|
+
console.log('\nโ ๏ธ SECURITY REMINDER:');
|
|
175
|
+
console.log('- Only update hashes after verifying changes are legitimate');
|
|
176
|
+
console.log('- Review git diff before updating hash values');
|
|
177
|
+
console.log('- Consider requiring code review for hash updates');
|
|
178
|
+
return configCode;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Enhanced security warning system for hash mismatches
|
|
182
|
+
*
|
|
183
|
+
* @param result - Hash verification result
|
|
184
|
+
* @param options - Warning options
|
|
185
|
+
*/
|
|
186
|
+
function handleHashMismatch(result, options = {}) {
|
|
187
|
+
if (result.isValid)
|
|
188
|
+
return;
|
|
189
|
+
const { throwOnMismatch = false, logLevel = 'error', onMismatch } = options;
|
|
190
|
+
const securityAlert = [
|
|
191
|
+
'๐จ๐จ๐จ CRITICAL SECURITY ALERT ๐จ๐จ๐จ',
|
|
192
|
+
`File: ${result.file}`,
|
|
193
|
+
`Reason: ${result.reason}`,
|
|
194
|
+
`Expected Hash: ${result.expectedHash}`,
|
|
195
|
+
`Actual Hash: ${result.actualHash}`,
|
|
196
|
+
'',
|
|
197
|
+
'โ ๏ธ POTENTIAL SECURITY BREACH DETECTED:',
|
|
198
|
+
'- File may have been tampered with',
|
|
199
|
+
'- Unauthorized modifications detected',
|
|
200
|
+
'- Supply chain attack possible',
|
|
201
|
+
'',
|
|
202
|
+
'๐ IMMEDIATE ACTIONS REQUIRED:',
|
|
203
|
+
'1. Stop using this package immediately',
|
|
204
|
+
'2. Investigate the source of file changes',
|
|
205
|
+
'3. Check git history for unauthorized commits',
|
|
206
|
+
'4. Verify file integrity from trusted source',
|
|
207
|
+
'5. Report security incident if confirmed',
|
|
208
|
+
'',
|
|
209
|
+
'๐ง Consider reporting to: security@[your-domain].com'
|
|
210
|
+
].join('\n');
|
|
211
|
+
if (logLevel === 'error') {
|
|
212
|
+
console.error(securityAlert);
|
|
213
|
+
}
|
|
214
|
+
else if (logLevel === 'warn') {
|
|
215
|
+
console.warn(securityAlert);
|
|
216
|
+
}
|
|
217
|
+
// Call custom handler if provided
|
|
218
|
+
if (onMismatch) {
|
|
219
|
+
onMismatch(result);
|
|
220
|
+
}
|
|
221
|
+
// Throw error if requested (for production environments)
|
|
222
|
+
if (throwOnMismatch) {
|
|
223
|
+
throw new Error(`SECURITY BREACH: Hash verification failed for ${result.file}. ` +
|
|
224
|
+
`Expected: ${result.expectedHash}, Got: ${result.actualHash}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Comprehensive security audit including hash verification
|
|
229
|
+
*
|
|
230
|
+
* @param providersFilePath - Path to providers JSON file
|
|
231
|
+
* @returns Complete security audit result
|
|
232
|
+
*/
|
|
233
|
+
function performSecurityAudit(providersFilePath) {
|
|
234
|
+
const filePath = providersFilePath || (0, path_1.join)(__dirname, '..', '..', 'providers', 'emailproviders.json');
|
|
235
|
+
const hashResult = verifyProvidersIntegrity(filePath);
|
|
236
|
+
const recommendations = [];
|
|
237
|
+
let securityLevel = 'HIGH';
|
|
238
|
+
if (!hashResult.isValid) {
|
|
239
|
+
securityLevel = 'CRITICAL';
|
|
240
|
+
recommendations.push('๐จ CRITICAL: File integrity check failed - investigate immediately');
|
|
241
|
+
recommendations.push('๐ Verify the source of the providers file');
|
|
242
|
+
recommendations.push('๐ Check git history for unauthorized changes');
|
|
243
|
+
}
|
|
244
|
+
if (KNOWN_GOOD_HASHES['emailproviders.json'] === 'TO_BE_CALCULATED') {
|
|
245
|
+
securityLevel = securityLevel === 'HIGH' ? 'MEDIUM' : securityLevel;
|
|
246
|
+
recommendations.push('โ๏ธ Configure expected hash values in production');
|
|
247
|
+
recommendations.push('๐ Store hashes in secure environment variables');
|
|
248
|
+
}
|
|
249
|
+
recommendations.push('๐ Regularly update hash values when making legitimate changes');
|
|
250
|
+
recommendations.push('๐ Monitor for unexpected hash changes in CI/CD');
|
|
251
|
+
recommendations.push('๐ก๏ธ Consider implementing digital signatures for additional security');
|
|
252
|
+
return {
|
|
253
|
+
hashVerification: hashResult,
|
|
254
|
+
recommendations,
|
|
255
|
+
securityLevel
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Creates a signed manifest of all provider URLs with their hashes
|
|
260
|
+
* This can be used to detect any URL modifications
|
|
261
|
+
*
|
|
262
|
+
* @param providers - Array of email providers
|
|
263
|
+
* @returns Signed manifest with URL hashes
|
|
264
|
+
*/
|
|
265
|
+
function createProviderManifest(providers) {
|
|
266
|
+
const urlHashes = {};
|
|
267
|
+
for (const provider of providers) {
|
|
268
|
+
if (provider.loginUrl) {
|
|
269
|
+
const key = `${provider.companyProvider}::${provider.loginUrl}`;
|
|
270
|
+
urlHashes[key] = calculateHash(provider.loginUrl);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const manifestData = {
|
|
274
|
+
timestamp: new Date().toISOString(),
|
|
275
|
+
providerCount: providers.length,
|
|
276
|
+
urlHashes
|
|
277
|
+
};
|
|
278
|
+
const manifestHash = calculateHash(JSON.stringify(manifestData, null, 2));
|
|
279
|
+
return {
|
|
280
|
+
...manifestData,
|
|
281
|
+
manifestHash
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=hash-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-verifier.js","sourceRoot":"","sources":["../../src/security/hash-verifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure Loader for Email Providers
|
|
3
|
+
*
|
|
4
|
+
* Integrates URL validation and hash verification to create a secure
|
|
5
|
+
* loading system for email provider data.
|
|
6
|
+
*/
|
|
7
|
+
import type { EmailProvider } from '../index';
|
|
8
|
+
export interface SecureLoadResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
providers: EmailProvider[];
|
|
11
|
+
securityReport: {
|
|
12
|
+
hashVerification: boolean;
|
|
13
|
+
urlValidation: boolean;
|
|
14
|
+
totalProviders: number;
|
|
15
|
+
validUrls: number;
|
|
16
|
+
invalidUrls: number;
|
|
17
|
+
securityLevel: 'SECURE' | 'WARNING' | 'CRITICAL';
|
|
18
|
+
issues: string[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Securely loads and validates email provider data
|
|
23
|
+
*
|
|
24
|
+
* @param providersPath - Path to the providers JSON file
|
|
25
|
+
* @param expectedHash - Optional expected hash for verification
|
|
26
|
+
* @returns Secure load result with validation details
|
|
27
|
+
*/
|
|
28
|
+
export declare function secureLoadProviders(providersPath?: string, expectedHash?: string): SecureLoadResult;
|
|
29
|
+
/**
|
|
30
|
+
* Development utility to generate and display current hashes
|
|
31
|
+
*/
|
|
32
|
+
export declare function initializeSecurity(): Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Express middleware for secure provider loading (if using in web apps)
|
|
35
|
+
*/
|
|
36
|
+
export declare function createSecurityMiddleware(options?: {
|
|
37
|
+
expectedHash?: string;
|
|
38
|
+
allowInvalidUrls?: boolean;
|
|
39
|
+
onSecurityIssue?: (report: SecureLoadResult['securityReport']) => void;
|
|
40
|
+
}): (req: any, res: any, next: any) => any;
|
|
41
|
+
declare const _default: {
|
|
42
|
+
secureLoadProviders: typeof secureLoadProviders;
|
|
43
|
+
initializeSecurity: typeof initializeSecurity;
|
|
44
|
+
createSecurityMiddleware: typeof createSecurityMiddleware;
|
|
45
|
+
};
|
|
46
|
+
export default _default;
|
|
47
|
+
//# sourceMappingURL=secure-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-loader.d.ts","sourceRoot":"","sources":["../../src/security/secure-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,cAAc,EAAE;QACd,gBAAgB,EAAE,OAAO,CAAC;QAC1B,aAAa,EAAE,OAAO,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;QACjD,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,CAAC,EAAE,MAAM,EACtB,YAAY,CAAC,EAAE,MAAM,GACpB,gBAAgB,CAoFlB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,2BAWjC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,GAAE;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;CACnE,IACI,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,MAAM,GAAG,SAmBtC;;;;;;AAED,wBAIE"}
|
|
@@ -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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-validator.js","sourceRoot":"","sources":["../../src/security/url-validator.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikkelscheike/email-provider-links",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "A TypeScript package that provides direct links to email providers based on email addresses to streamline login and password reset flows",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|