spamscanner 6.0.0 → 6.1.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.
- package/README.md +569 -42
- package/dist/cjs/arf.cjs +539 -0
- package/dist/cjs/arf.cjs.map +7 -0
- package/dist/cjs/cli.cjs +4729 -0
- package/dist/cjs/cli.cjs.map +7 -0
- package/dist/cjs/{index.js → index.cjs} +1677 -52
- package/dist/cjs/index.cjs.map +7 -0
- package/dist/esm/arf.js +514 -0
- package/dist/esm/arf.js.map +7 -0
- package/dist/esm/cli.js +4713 -0
- package/dist/esm/cli.js.map +7 -0
- package/dist/esm/index.js +1676 -51
- package/dist/esm/index.js.map +4 -4
- package/dist/types/arf.d.ts +129 -0
- package/dist/types/auth.d.ts +157 -0
- package/dist/types/enhanced-idn-detector.d.ts +236 -0
- package/dist/types/get-attributes.d.ts +148 -0
- package/dist/types/index.d.ts +959 -0
- package/dist/types/is-arbitrary.d.ts +231 -0
- package/dist/types/reputation.d.ts +60 -0
- package/package.json +13 -4
- package/dist/cjs/index.js.map +0 -7
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ARF (Abuse Reporting Format) Parser Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* @see https://www.rfc-editor.org/rfc/rfc5965.html
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Valid feedback types as defined in RFC 5965 and extensions
|
|
9
|
+
*/
|
|
10
|
+
export declare const VALID_FEEDBACK_TYPES: Set<string>;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Reporting MTA information
|
|
14
|
+
*/
|
|
15
|
+
export interface ReportingMta {
|
|
16
|
+
/** MTA type (dns, smtp, etc.) */
|
|
17
|
+
type: string;
|
|
18
|
+
/** MTA hostname */
|
|
19
|
+
name: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Parsed ARF report result
|
|
24
|
+
*/
|
|
25
|
+
export interface ArfResult {
|
|
26
|
+
/** Whether this is a valid ARF message */
|
|
27
|
+
isArf: boolean;
|
|
28
|
+
/** ARF version (usually "1") */
|
|
29
|
+
version: string | null;
|
|
30
|
+
/** Feedback type (abuse, fraud, virus, other, not-spam, auth-failure, dmarc) */
|
|
31
|
+
feedbackType: string | null;
|
|
32
|
+
/** Original feedback type if it was normalized to "other" */
|
|
33
|
+
feedbackTypeOriginal?: string;
|
|
34
|
+
/** User agent that generated the report */
|
|
35
|
+
userAgent: string | null;
|
|
36
|
+
/** Arrival date of the original message */
|
|
37
|
+
arrivalDate: Date | null;
|
|
38
|
+
/** Source IP address of the original message */
|
|
39
|
+
sourceIp: string | null;
|
|
40
|
+
/** Original MAIL FROM address */
|
|
41
|
+
originalMailFrom: string | null;
|
|
42
|
+
/** Original RCPT TO addresses */
|
|
43
|
+
originalRcptTo: string[] | null;
|
|
44
|
+
/** Reporting MTA information */
|
|
45
|
+
reportingMta: ReportingMta | null;
|
|
46
|
+
/** Original envelope ID */
|
|
47
|
+
originalEnvelopeId: string | null;
|
|
48
|
+
/** Authentication results */
|
|
49
|
+
authenticationResults: string[] | null;
|
|
50
|
+
/** Reported domains */
|
|
51
|
+
reportedDomain: string[] | null;
|
|
52
|
+
/** Reported URIs */
|
|
53
|
+
reportedUri: string[] | null;
|
|
54
|
+
/** Number of incidents */
|
|
55
|
+
incidents: number;
|
|
56
|
+
/** Human-readable description */
|
|
57
|
+
humanReadable: string | null;
|
|
58
|
+
/** Original message content */
|
|
59
|
+
originalMessage: string | null;
|
|
60
|
+
/** Parsed headers from original message */
|
|
61
|
+
originalHeaders: Record<string, unknown> | null;
|
|
62
|
+
/** Raw feedback report content */
|
|
63
|
+
rawFeedbackReport: string | null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Options for creating an ARF report
|
|
68
|
+
*/
|
|
69
|
+
export interface ArfCreateOptions {
|
|
70
|
+
/** Feedback type (abuse, fraud, virus, other) */
|
|
71
|
+
feedbackType: string;
|
|
72
|
+
/** User agent string */
|
|
73
|
+
userAgent: string;
|
|
74
|
+
/** From address for the report */
|
|
75
|
+
from: string;
|
|
76
|
+
/** To address for the report */
|
|
77
|
+
to: string;
|
|
78
|
+
/** Original message content */
|
|
79
|
+
originalMessage: string;
|
|
80
|
+
/** Human-readable description */
|
|
81
|
+
humanReadable?: string;
|
|
82
|
+
/** Source IP of original message */
|
|
83
|
+
sourceIp?: string;
|
|
84
|
+
/** Original MAIL FROM address */
|
|
85
|
+
originalMailFrom?: string;
|
|
86
|
+
/** Original RCPT TO addresses */
|
|
87
|
+
originalRcptTo?: string[];
|
|
88
|
+
/** Arrival date of original message */
|
|
89
|
+
arrivalDate?: Date;
|
|
90
|
+
/** Reporting MTA name */
|
|
91
|
+
reportingMta?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* ARF Parser class for parsing and creating ARF (Abuse Reporting Format) messages
|
|
96
|
+
*/
|
|
97
|
+
export declare class ArfParser {
|
|
98
|
+
/**
|
|
99
|
+
* Check if a parsed email message is an ARF report
|
|
100
|
+
* @param parsed - Parsed email message from mailparser
|
|
101
|
+
* @returns True if message is ARF
|
|
102
|
+
*/
|
|
103
|
+
static isArfMessage(parsed: unknown): boolean;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse an ARF message
|
|
107
|
+
* @param source - Raw email message as Buffer or string
|
|
108
|
+
* @returns Parsed ARF report
|
|
109
|
+
* @throws Error if not a valid ARF message
|
|
110
|
+
*/
|
|
111
|
+
static parse(source: Buffer | string): Promise<ArfResult>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Try to parse a message as ARF, return null if not ARF
|
|
115
|
+
* @param source - Raw email message as Buffer or string
|
|
116
|
+
* @returns Parsed ARF report or null if not ARF
|
|
117
|
+
*/
|
|
118
|
+
static tryParse(source: Buffer | string): Promise<ArfResult | null>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Create an ARF report message
|
|
122
|
+
* @param options - Report options
|
|
123
|
+
* @returns ARF message as string
|
|
124
|
+
* @throws Error if missing required fields
|
|
125
|
+
*/
|
|
126
|
+
static create(options: ArfCreateOptions): string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export default ArfParser;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Email Authentication Module Type Definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface DkimResult {
|
|
6
|
+
results: DkimSignatureResult[];
|
|
7
|
+
status: AuthStatus;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface DkimSignatureResult {
|
|
11
|
+
signingDomain?: string;
|
|
12
|
+
selector?: string;
|
|
13
|
+
algo?: string;
|
|
14
|
+
format?: string;
|
|
15
|
+
signature?: string;
|
|
16
|
+
bodyHash?: string;
|
|
17
|
+
status: AuthStatus;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SpfResult {
|
|
21
|
+
status: AuthStatus;
|
|
22
|
+
domain: string | null;
|
|
23
|
+
explanation?: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DmarcResult {
|
|
27
|
+
status: AuthStatus;
|
|
28
|
+
policy: string | null;
|
|
29
|
+
domain: string | null;
|
|
30
|
+
p?: string | null;
|
|
31
|
+
sp?: string | null;
|
|
32
|
+
pct?: number | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ArcResult {
|
|
36
|
+
status: AuthStatus;
|
|
37
|
+
chain: ArcChainEntry[];
|
|
38
|
+
i?: number | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ArcChainEntry {
|
|
42
|
+
i: number;
|
|
43
|
+
cv: string;
|
|
44
|
+
status: AuthStatus;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface BimiResult {
|
|
48
|
+
status: AuthStatus;
|
|
49
|
+
location: string | null;
|
|
50
|
+
authority: string | null;
|
|
51
|
+
selector?: string | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface AuthStatus {
|
|
55
|
+
result: 'pass' | 'fail' | 'softfail' | 'neutral' | 'none' | 'temperror' | 'permerror';
|
|
56
|
+
comment?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface AuthResult {
|
|
60
|
+
dkim: DkimResult;
|
|
61
|
+
spf: SpfResult;
|
|
62
|
+
dmarc: DmarcResult;
|
|
63
|
+
arc: ArcResult;
|
|
64
|
+
bimi: BimiResult;
|
|
65
|
+
receivedChain: ReceivedChainEntry[];
|
|
66
|
+
headers: Record<string, string>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ReceivedChainEntry {
|
|
70
|
+
from?: string;
|
|
71
|
+
by?: string;
|
|
72
|
+
with?: string;
|
|
73
|
+
id?: string;
|
|
74
|
+
for?: string;
|
|
75
|
+
date?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface AuthOptions {
|
|
79
|
+
ip: string;
|
|
80
|
+
helo?: string;
|
|
81
|
+
mta?: string;
|
|
82
|
+
sender?: string;
|
|
83
|
+
resolver?: (name: string, type: string) => Promise<string[]>;
|
|
84
|
+
timeout?: number;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface AuthScoreWeights {
|
|
88
|
+
dkimPass?: number;
|
|
89
|
+
dkimFail?: number;
|
|
90
|
+
spfPass?: number;
|
|
91
|
+
spfFail?: number;
|
|
92
|
+
spfSoftfail?: number;
|
|
93
|
+
dmarcPass?: number;
|
|
94
|
+
dmarcFail?: number;
|
|
95
|
+
arcPass?: number;
|
|
96
|
+
arcFail?: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface AuthScoreResult {
|
|
100
|
+
score: number;
|
|
101
|
+
tests: string[];
|
|
102
|
+
details: {
|
|
103
|
+
dkim: string;
|
|
104
|
+
spf: string;
|
|
105
|
+
dmarc: string;
|
|
106
|
+
arc: string;
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Authenticate an email message
|
|
112
|
+
*/
|
|
113
|
+
export function authenticate(
|
|
114
|
+
message: Buffer | string,
|
|
115
|
+
options?: AuthOptions
|
|
116
|
+
): Promise<AuthResult>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Perform SPF check only
|
|
120
|
+
*/
|
|
121
|
+
export function checkSpf(
|
|
122
|
+
ip: string,
|
|
123
|
+
sender: string,
|
|
124
|
+
helo?: string,
|
|
125
|
+
options?: Partial<AuthOptions>
|
|
126
|
+
): Promise<SpfResult>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Verify DKIM signature
|
|
130
|
+
*/
|
|
131
|
+
export function verifyDkim(
|
|
132
|
+
message: Buffer | string,
|
|
133
|
+
options?: Partial<AuthOptions>
|
|
134
|
+
): Promise<DkimResult>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Calculate authentication score based on results
|
|
138
|
+
*/
|
|
139
|
+
export function calculateAuthScore(
|
|
140
|
+
authResult: AuthResult,
|
|
141
|
+
weights?: AuthScoreWeights
|
|
142
|
+
): AuthScoreResult;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Format authentication results as Authentication-Results header
|
|
146
|
+
*/
|
|
147
|
+
export function formatAuthResultsHeader(
|
|
148
|
+
authResult: AuthResult,
|
|
149
|
+
hostname?: string
|
|
150
|
+
): string;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Create a DNS resolver with timeout support
|
|
154
|
+
*/
|
|
155
|
+
export function createResolver(
|
|
156
|
+
timeout?: number
|
|
157
|
+
): (name: string, type: string) => Promise<string[]>;
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced IDN Detector options
|
|
3
|
+
*/
|
|
4
|
+
export type EnhancedIdnDetectorOptions = {
|
|
5
|
+
/** Enable strict mode */
|
|
6
|
+
strictMode?: boolean;
|
|
7
|
+
/** Enable domain whitelist */
|
|
8
|
+
enableWhitelist?: boolean;
|
|
9
|
+
/** Enable brand protection */
|
|
10
|
+
enableBrandProtection?: boolean;
|
|
11
|
+
/** Enable context analysis */
|
|
12
|
+
enableContextAnalysis?: boolean;
|
|
13
|
+
/** Maximum similarity threshold (0-1) */
|
|
14
|
+
maxSimilarityThreshold?: number;
|
|
15
|
+
/** Minimum domain age in days */
|
|
16
|
+
minDomainAge?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Context for IDN analysis
|
|
21
|
+
*/
|
|
22
|
+
export type IdnAnalysisContext = {
|
|
23
|
+
/** Email content */
|
|
24
|
+
emailContent?: string;
|
|
25
|
+
/** Display text (if different from domain) */
|
|
26
|
+
displayText?: string | undefined;
|
|
27
|
+
/** Sender reputation (0-1) */
|
|
28
|
+
senderReputation?: number;
|
|
29
|
+
/** Email headers */
|
|
30
|
+
emailHeaders?: Map<string, unknown> | Record<string, unknown>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* IDN analysis result
|
|
35
|
+
*/
|
|
36
|
+
export type IdnAnalysisResult = {
|
|
37
|
+
/** The domain analyzed */
|
|
38
|
+
domain: string;
|
|
39
|
+
/** Whether the domain is an IDN */
|
|
40
|
+
isIdn: boolean;
|
|
41
|
+
/** Risk score (0-1) */
|
|
42
|
+
riskScore: number;
|
|
43
|
+
/** Risk factors identified */
|
|
44
|
+
riskFactors: string[];
|
|
45
|
+
/** Recommendations */
|
|
46
|
+
recommendations: string[];
|
|
47
|
+
/** Confidence level (0-1) */
|
|
48
|
+
confidence: number;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Confusable character analysis result
|
|
53
|
+
*/
|
|
54
|
+
export type ConfusableAnalysis = {
|
|
55
|
+
/** Risk score contribution */
|
|
56
|
+
score: number;
|
|
57
|
+
/** Risk factors identified */
|
|
58
|
+
factors: string[];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Brand similarity analysis result
|
|
63
|
+
*/
|
|
64
|
+
export type BrandAnalysis = {
|
|
65
|
+
/** Risk score contribution */
|
|
66
|
+
score: number;
|
|
67
|
+
/** Risk factors identified */
|
|
68
|
+
factors: string[];
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Script mixing analysis result
|
|
73
|
+
*/
|
|
74
|
+
export type ScriptAnalysis = {
|
|
75
|
+
/** Risk score contribution */
|
|
76
|
+
score: number;
|
|
77
|
+
/** Risk factors identified */
|
|
78
|
+
factors: string[];
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Context analysis result
|
|
83
|
+
*/
|
|
84
|
+
export type ContextAnalysis = {
|
|
85
|
+
/** Risk score contribution */
|
|
86
|
+
score: number;
|
|
87
|
+
/** Risk factors identified */
|
|
88
|
+
factors: string[];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Punycode analysis result
|
|
93
|
+
*/
|
|
94
|
+
export type PunycodeAnalysis = {
|
|
95
|
+
/** Risk score contribution */
|
|
96
|
+
score: number;
|
|
97
|
+
/** Risk factors identified */
|
|
98
|
+
factors: string[];
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Enhanced IDN Homograph Attack Detector
|
|
103
|
+
*/
|
|
104
|
+
declare class EnhancedIdnDetector {
|
|
105
|
+
/** Detector options */
|
|
106
|
+
options: EnhancedIdnDetectorOptions & {
|
|
107
|
+
strictMode: boolean;
|
|
108
|
+
enableWhitelist: boolean;
|
|
109
|
+
enableBrandProtection: boolean;
|
|
110
|
+
enableContextAnalysis: boolean;
|
|
111
|
+
maxSimilarityThreshold: number;
|
|
112
|
+
minDomainAge: number;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/** Analysis cache */
|
|
116
|
+
cache: Map<string, IdnAnalysisResult>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Create a new EnhancedIdnDetector instance
|
|
120
|
+
* @param options - Configuration options
|
|
121
|
+
*/
|
|
122
|
+
constructor(options?: EnhancedIdnDetectorOptions);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Detect homograph attack in a domain
|
|
126
|
+
* @param domain - Domain to analyze
|
|
127
|
+
* @param context - Analysis context
|
|
128
|
+
* @returns Analysis result
|
|
129
|
+
*/
|
|
130
|
+
detectHomographAttack(domain: string, context?: IdnAnalysisContext): IdnAnalysisResult;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Comprehensive analysis of a domain
|
|
134
|
+
* @param domain - Domain to analyze
|
|
135
|
+
* @param context - Analysis context
|
|
136
|
+
* @returns Analysis result
|
|
137
|
+
*/
|
|
138
|
+
analyzeComprehensive(domain: string, context: IdnAnalysisContext): IdnAnalysisResult;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if domain contains IDN characters
|
|
142
|
+
* @param domain - Domain to check
|
|
143
|
+
* @returns Whether the domain is an IDN
|
|
144
|
+
*/
|
|
145
|
+
isIdnDomain(domain: string): boolean;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if domain is whitelisted
|
|
149
|
+
* @param domain - Domain to check
|
|
150
|
+
* @returns Whether the domain is whitelisted
|
|
151
|
+
*/
|
|
152
|
+
isWhitelisted(domain: string): boolean;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Analyze confusable characters in domain
|
|
156
|
+
* @param domain - Domain to analyze
|
|
157
|
+
* @returns Confusable analysis result
|
|
158
|
+
*/
|
|
159
|
+
analyzeConfusableCharacters(domain: string): ConfusableAnalysis;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Analyze brand similarity
|
|
163
|
+
* @param domain - Domain to analyze
|
|
164
|
+
* @returns Brand analysis result
|
|
165
|
+
*/
|
|
166
|
+
analyzeBrandSimilarity(domain: string): BrandAnalysis;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Analyze script mixing patterns
|
|
170
|
+
* @param domain - Domain to analyze
|
|
171
|
+
* @returns Script analysis result
|
|
172
|
+
*/
|
|
173
|
+
analyzeScriptMixing(domain: string): ScriptAnalysis;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Analyze context for additional risk factors
|
|
177
|
+
* @param domain - Domain to analyze
|
|
178
|
+
* @param context - Analysis context
|
|
179
|
+
* @returns Context analysis result
|
|
180
|
+
*/
|
|
181
|
+
analyzeContext(domain: string, context: IdnAnalysisContext): ContextAnalysis;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Analyze punycode domain
|
|
185
|
+
* @param domain - Domain to analyze
|
|
186
|
+
* @returns Punycode analysis result
|
|
187
|
+
*/
|
|
188
|
+
analyzePunycode(domain: string): PunycodeAnalysis;
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Normalize domain for comparison
|
|
192
|
+
* @param domain - Domain to normalize
|
|
193
|
+
* @returns Normalized domain
|
|
194
|
+
*/
|
|
195
|
+
normalizeDomain(domain: string): string;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Calculate string similarity using Levenshtein distance
|
|
199
|
+
* @param string1 - First string
|
|
200
|
+
* @param string2 - Second string
|
|
201
|
+
* @returns Similarity score (0-1)
|
|
202
|
+
*/
|
|
203
|
+
calculateSimilarity(string1: string, string2: string): number;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Detect scripts used in domain
|
|
207
|
+
* @param domain - Domain to analyze
|
|
208
|
+
* @returns Set of detected scripts
|
|
209
|
+
*/
|
|
210
|
+
detectScripts(domain: string): Set<string>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Decode punycode domain
|
|
214
|
+
* @param domain - Domain to decode
|
|
215
|
+
* @returns Decoded domain
|
|
216
|
+
*/
|
|
217
|
+
decodePunycode(domain: string): string;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Generate recommendations based on analysis
|
|
221
|
+
* @param analysis - Analysis result
|
|
222
|
+
* @returns Array of recommendations
|
|
223
|
+
*/
|
|
224
|
+
generateRecommendations(analysis: IdnAnalysisResult): string[];
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get cache key for analysis
|
|
228
|
+
* @param domain - Domain
|
|
229
|
+
* @param context - Analysis context
|
|
230
|
+
* @returns Cache key
|
|
231
|
+
*/
|
|
232
|
+
getCacheKey(domain: string, context: IdnAnalysisContext): string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export default EnhancedIdnDetector;
|
|
236
|
+
export {EnhancedIdnDetector};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get Attributes Module Type Definitions
|
|
3
|
+
* Based on Forward Email's get-attributes helper
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {AuthenticationResults} from './auth';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Session information for attribute extraction
|
|
10
|
+
*/
|
|
11
|
+
export interface SessionInfo {
|
|
12
|
+
/** Resolved hostname of connecting client */
|
|
13
|
+
resolvedClientHostname?: string;
|
|
14
|
+
/** Root domain of resolved client hostname */
|
|
15
|
+
resolvedRootClientHostname?: string;
|
|
16
|
+
/** IP address of connecting client */
|
|
17
|
+
remoteAddress?: string;
|
|
18
|
+
/** Email address from From header */
|
|
19
|
+
originalFromAddress?: string;
|
|
20
|
+
/** Domain from From header */
|
|
21
|
+
originalFromAddressDomain?: string;
|
|
22
|
+
/** Root domain from From header */
|
|
23
|
+
originalFromAddressRootDomain?: string;
|
|
24
|
+
/** SMTP envelope */
|
|
25
|
+
envelope?: {
|
|
26
|
+
mailFrom?: {address: string};
|
|
27
|
+
rcptTo?: Array<{address: string}>;
|
|
28
|
+
};
|
|
29
|
+
/** Whether DKIM was aligned and passing */
|
|
30
|
+
hadAlignedAndPassingDKIM?: boolean;
|
|
31
|
+
/** SPF result for From header */
|
|
32
|
+
spfFromHeader?: {
|
|
33
|
+
status?: {result: string};
|
|
34
|
+
};
|
|
35
|
+
/** Whether client hostname matches From domain */
|
|
36
|
+
hasSameHostnameAsFrom?: boolean;
|
|
37
|
+
/** Whether sender is allowlisted */
|
|
38
|
+
isAllowlisted?: boolean;
|
|
39
|
+
/** Set of DKIM signing domains */
|
|
40
|
+
signingDomains?: Set<string>;
|
|
41
|
+
/** SPF domain */
|
|
42
|
+
spf?: {
|
|
43
|
+
domain?: string;
|
|
44
|
+
};
|
|
45
|
+
/** Whether message is potential phishing */
|
|
46
|
+
isPotentialPhishing?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Options for attribute extraction
|
|
51
|
+
*/
|
|
52
|
+
export interface GetAttributesOptions {
|
|
53
|
+
/** Only return attributes that are verified and aligned */
|
|
54
|
+
isAligned?: boolean;
|
|
55
|
+
/** Authentication results from mailauth */
|
|
56
|
+
authResults?: AuthenticationResults | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Options for extractAttributes convenience function
|
|
61
|
+
*/
|
|
62
|
+
export interface ExtractAttributesOptions extends GetAttributesOptions {
|
|
63
|
+
/** Sender IP address */
|
|
64
|
+
senderIp?: string;
|
|
65
|
+
/** Sender hostname */
|
|
66
|
+
senderHostname?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Result from extractAttributes
|
|
71
|
+
*/
|
|
72
|
+
export interface ExtractAttributesResult {
|
|
73
|
+
/** Array of unique attributes to check */
|
|
74
|
+
attributes: string[];
|
|
75
|
+
/** Session information built from parsed email */
|
|
76
|
+
session: SessionInfo;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get attributes from an email for reputation checking
|
|
81
|
+
* @param parsed - Parsed email message
|
|
82
|
+
* @param session - Session information
|
|
83
|
+
* @param options - Options
|
|
84
|
+
* @returns Array of unique attributes to check
|
|
85
|
+
*/
|
|
86
|
+
export function getAttributes(
|
|
87
|
+
parsed: object,
|
|
88
|
+
session?: SessionInfo,
|
|
89
|
+
options?: GetAttributesOptions,
|
|
90
|
+
): Promise<string[]>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Build session info from parsed email
|
|
94
|
+
* @param parsed - Parsed email
|
|
95
|
+
* @param existingSession - Existing session info to merge
|
|
96
|
+
* @returns Session information
|
|
97
|
+
*/
|
|
98
|
+
export function buildSessionFromParsed(
|
|
99
|
+
parsed: object,
|
|
100
|
+
existingSession?: Partial<SessionInfo>,
|
|
101
|
+
): SessionInfo;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Extract all checkable attributes from an email
|
|
105
|
+
* @param parsed - Parsed email message
|
|
106
|
+
* @param options - Options
|
|
107
|
+
* @returns Attributes and session info
|
|
108
|
+
*/
|
|
109
|
+
export function extractAttributes(
|
|
110
|
+
parsed: object,
|
|
111
|
+
options?: ExtractAttributesOptions,
|
|
112
|
+
): Promise<ExtractAttributesResult>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Check and remove SRS (Sender Rewriting Scheme) encoding from an address
|
|
116
|
+
* @param address - Email address
|
|
117
|
+
* @returns Address with SRS removed
|
|
118
|
+
*/
|
|
119
|
+
export function checkSRS(address: string): string;
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Parse host/domain from an email address or domain string
|
|
123
|
+
* @param addressOrDomain - Email address or domain
|
|
124
|
+
* @returns Domain portion
|
|
125
|
+
*/
|
|
126
|
+
export function parseHostFromDomainOrAddress(addressOrDomain: string): string;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get root domain from a hostname
|
|
130
|
+
* @param hostname - Hostname
|
|
131
|
+
* @returns Root domain
|
|
132
|
+
*/
|
|
133
|
+
export function parseRootDomain(hostname: string): string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Parse addresses from a header value
|
|
137
|
+
* @param headerValue - Header value
|
|
138
|
+
* @returns Array of email addresses
|
|
139
|
+
*/
|
|
140
|
+
export function parseAddresses(headerValue: string | object | unknown[]): string[];
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get header value from parsed email
|
|
144
|
+
* @param headers - Headers object
|
|
145
|
+
* @param name - Header name
|
|
146
|
+
* @returns Header value or null
|
|
147
|
+
*/
|
|
148
|
+
export function getHeaders(headers: object, name: string): string | null;
|