/
receipt-rule.ts
207 lines (177 loc) · 5.17 KB
/
receipt-rule.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import { Construct } from 'constructs';
import { IReceiptRuleAction } from './receipt-rule-action';
import { IReceiptRuleSet } from './receipt-rule-set';
import { CfnReceiptRule } from './ses.generated';
import * as iam from '../../aws-iam';
import { Aws, IResource, Lazy, Resource } from '../../core';
import { DropSpamSingletonFunction } from '../../custom-resource-handlers/dist/aws-ses/drop-spam-provider.generated';
/**
* A receipt rule.
*/
export interface IReceiptRule extends IResource {
/**
* The name of the receipt rule.
* @attribute
*/
readonly receiptRuleName: string;
}
/**
* The type of TLS policy for a receipt rule.
*/
export enum TlsPolicy {
/**
* Do not check for TLS.
*/
OPTIONAL = 'Optional',
/**
* Bounce emails that are not received over TLS.
*/
REQUIRE = 'Require',
}
/**
* Options to add a receipt rule to a receipt rule set.
*/
export interface ReceiptRuleOptions {
/**
* An ordered list of actions to perform on messages that match at least
* one of the recipient email addresses or domains specified in the
* receipt rule.
*
* @default - No actions.
*/
readonly actions?: IReceiptRuleAction[];
/**
* An existing rule after which the new rule will be placed.
*
* @default - The new rule is inserted at the beginning of the rule list.
*/
readonly after?: IReceiptRule;
/**
* Whether the rule is active.
*
* @default true
*/
readonly enabled?: boolean;
/**
* The name for the rule
*
* @default - A CloudFormation generated name.
*/
readonly receiptRuleName?: string;
/**
* The recipient domains and email addresses that the receipt rule applies to.
*
* @default - Match all recipients under all verified domains.
*/
readonly recipients?: string[];
/**
* Whether to scan for spam and viruses.
*
* @default false
*/
readonly scanEnabled?: boolean;
/**
* Whether Amazon SES should require that incoming email is delivered over a
* connection encrypted with Transport Layer Security (TLS).
*
* @default - Optional which will not check for TLS.
*/
readonly tlsPolicy?: TlsPolicy;
}
/**
* Construction properties for a ReceiptRule.
*/
export interface ReceiptRuleProps extends ReceiptRuleOptions {
/**
* The name of the rule set that the receipt rule will be added to.
*/
readonly ruleSet: IReceiptRuleSet;
}
/**
* A new receipt rule.
*/
export class ReceiptRule extends Resource implements IReceiptRule {
public static fromReceiptRuleName(scope: Construct, id: string, receiptRuleName: string): IReceiptRule {
class Import extends Resource implements IReceiptRule {
public readonly receiptRuleName = receiptRuleName;
}
return new Import(scope, id);
}
public readonly receiptRuleName: string;
private readonly ruleSet: IReceiptRuleSet;
private readonly actions: IReceiptRuleAction[] = [];
private readonly actionProperties: CfnReceiptRule.ActionProperty[] = [];
constructor(scope: Construct, id: string, props: ReceiptRuleProps) {
super(scope, id, {
physicalName: props.receiptRuleName,
});
const resource = new CfnReceiptRule(this, 'Resource', {
after: props.after?.receiptRuleName,
rule: {
actions: Lazy.any({ produce: () => this.renderActions() }),
enabled: props.enabled ?? true,
name: this.physicalName,
recipients: props.recipients,
scanEnabled: props.scanEnabled,
tlsPolicy: props.tlsPolicy,
},
ruleSetName: props.ruleSet.receiptRuleSetName,
});
this.receiptRuleName = resource.ref;
this.ruleSet = props.ruleSet;
for (const action of props.actions || []) {
this.addAction(action);
}
}
/**
* Adds an action to this receipt rule.
*/
public addAction(action: IReceiptRuleAction) {
this.actions.push(action);
this.actionProperties.push(action.bind(this));
}
private renderActions() {
if (this.actionProperties.length === 0) {
return undefined;
}
for (const action of this.actions) {
action._applyPolicyStatement?.(this.ruleSet);
}
return this.actionProperties;
}
}
export interface DropSpamReceiptRuleProps extends ReceiptRuleProps {
}
/**
* A rule added at the top of the rule set to drop spam/virus.
*
* @see https://docs.aws.amazon.com/ses/latest/DeveloperGuide/receiving-email-action-lambda-example-functions.html
*/
export class DropSpamReceiptRule extends Construct {
public readonly rule: ReceiptRule;
constructor(scope: Construct, id: string, props: DropSpamReceiptRuleProps) {
super(scope, id);
const fn = new DropSpamSingletonFunction(this, 'Function', {
uuid: '224e77f9-a32e-4b4d-ac32-983477abba16',
});
fn.addPermission('AllowSes', {
action: 'lambda:InvokeFunction',
principal: new iam.ServicePrincipal('ses.amazonaws.com'),
sourceAccount: Aws.ACCOUNT_ID,
});
this.rule = new ReceiptRule(this, 'Rule', {
actions: [
{
bind: () => ({
lambdaAction: {
functionArn: fn.functionArn,
invocationType: 'RequestResponse',
},
}),
},
],
scanEnabled: true,
ruleSet: props.ruleSet,
});
}
}