@mavogel/awscdk-rootmail 0.0.17 → 0.0.18

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.
Files changed (39) hide show
  1. package/.jsii +50 -16
  2. package/API.md +95 -2
  3. package/README.md +69 -2
  4. package/docs/img/cloudformation-tpl-min.png +0 -0
  5. package/integ-tests/functions/custom-ses-receive-function.ts +92 -0
  6. package/integ-tests/integ.rootmail-custom-santa.ts +143 -0
  7. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/RootmailIntegTestStack.assets.json +162 -0
  8. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/RootmailIntegTestStack.template.json +4541 -0
  9. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/SetupTestIntegStackDefaultTestDeployAssert6EB6FF77.assets.json +32 -0
  10. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/SetupTestIntegStackDefaultTestDeployAssert6EB6FF77.template.json +249 -0
  11. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.0649b5bfaa322d6bd173d2daef3177389cf0778b556b300ac6bf451704cc3a49/index.js +37981 -0
  12. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.157ba1713f7224463b621261792d18081588ff306a9bc3f75e6c468fabbe1a60/index.js +106 -0
  13. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.4c079063901e6478dbb5ace19e3123641ebf0da2ab648ecf52079c5bec154196/index.js +215 -0
  14. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.53e8368959effe94a6e51bef9c7c5bf0eaf5c4d64eece81632ca62aa34517978.bundle/index.js +31981 -0
  15. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.5cc92ed0cea39e2b8de2dbc527dfb5980a3af9564bd1084d840b9787c7d0467e/index.d.ts +14 -0
  16. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.5cc92ed0cea39e2b8de2dbc527dfb5980a3af9564bd1084d840b9787c7d0467e/index.js +1 -0
  17. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.78b64aaf9aebb4eacbdd42197be10e9d5894360a642f7dcf79aeb84bb3552377/index.js +61 -0
  18. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.7e8a681794eff5fda1841caa360113df5488ecf944055a69b8f1e5a687e269f5/index.js +83 -0
  19. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.9572b451243318765beb576ae7528096b3879783dbaab795c02c01d7f4e83438/index.js +47 -0
  20. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.b8448324ef2c7d5bfa362722df2d397079d5aabaae2749f09180ac5bedfa5c89/index.js +105 -0
  21. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.d2b520d86fd9d964c83dc0d5ce2e4456dbde5fa7ae0c791a71865cbdfe2fb855/index.js +85 -0
  22. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f2d30cfc360482320a52a4fcde8a70f3569df79ab30be24650fda58eb60052cf/cfn-response.js +1 -0
  23. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f2d30cfc360482320a52a4fcde8a70f3569df79ab30be24650fda58eb60052cf/consts.js +1 -0
  24. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f2d30cfc360482320a52a4fcde8a70f3569df79ab30be24650fda58eb60052cf/framework.js +3 -0
  25. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f2d30cfc360482320a52a4fcde8a70f3569df79ab30be24650fda58eb60052cf/outbound.js +1 -0
  26. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f2d30cfc360482320a52a4fcde8a70f3569df79ab30be24650fda58eb60052cf/util.js +1 -0
  27. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/asset.f9b17c134d24cf60e1d26c033b5f4f247b759149619ac0aac341b950a10ccf14/index.js +72 -0
  28. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/integ.json +27 -0
  29. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/manifest.json +742 -0
  30. package/integ-tests/integ.rootmail-custom-santa.ts.snapshot/tree.json +5893 -0
  31. package/integ-tests/integ.rootmail.ts.snapshot/SetupTestIntegStackDefaultTestDeployAssert6EB6FF77.assets.json +2 -2
  32. package/integ-tests/integ.rootmail.ts.snapshot/SetupTestIntegStackDefaultTestDeployAssert6EB6FF77.template.json +3 -3
  33. package/integ-tests/integ.rootmail.ts.snapshot/manifest.json +1 -1
  34. package/lib/index.js +2 -1
  35. package/lib/rootmail.d.ts +5 -1
  36. package/lib/rootmail.js +3 -2
  37. package/lib/ses-receive.d.ts +5 -1
  38. package/lib/ses-receive.js +36 -14
  39. package/package.json +2 -2
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/rootmail-autowire-dns.is-complete-handler.ts
21
+ var rootmail_autowire_dns_is_complete_handler_exports = {};
22
+ __export(rootmail_autowire_dns_is_complete_handler_exports, {
23
+ PROP_DOMAIN: () => PROP_DOMAIN,
24
+ PROP_PARENT_HOSTED_ZONE_ID: () => PROP_PARENT_HOSTED_ZONE_ID,
25
+ PROP_R53_HANGEINFO_ID_PARAMETER_NAME: () => PROP_R53_HANGEINFO_ID_PARAMETER_NAME,
26
+ PROP_SUB_DOMAIN: () => PROP_SUB_DOMAIN,
27
+ handler: () => handler
28
+ });
29
+ module.exports = __toCommonJS(rootmail_autowire_dns_is_complete_handler_exports);
30
+ var import_client_route_53 = require("@aws-sdk/client-route-53");
31
+ var import_client_ssm = require("@aws-sdk/client-ssm");
32
+ var PROP_DOMAIN = "Domain";
33
+ var PROP_SUB_DOMAIN = "Subdomain";
34
+ var PROP_R53_HANGEINFO_ID_PARAMETER_NAME = "R53ChangeInfoIdParameterName";
35
+ var PROP_PARENT_HOSTED_ZONE_ID = "ParentHostedZoneId";
36
+ var route53 = new import_client_route_53.Route53();
37
+ var ssm = new import_client_ssm.SSM();
38
+ async function handler(event) {
39
+ const domain = event.ResourceProperties[PROP_DOMAIN];
40
+ const subdomain = event.ResourceProperties[PROP_SUB_DOMAIN];
41
+ const hostedZoneParameterName = event.ResourceProperties[PROP_R53_HANGEINFO_ID_PARAMETER_NAME];
42
+ const parentHostedZoneId = event.ResourceProperties[PROP_PARENT_HOSTED_ZONE_ID];
43
+ if (parentHostedZoneId === void 0 || parentHostedZoneId === "") {
44
+ log(`Skipping autoDNS wiring on '${event.RequestType}' for domain '${subdomain}.${domain}' as no parentHostedZoneId is given!`);
45
+ return {
46
+ IsComplete: true
47
+ };
48
+ }
49
+ const recordSetCreationResponseChangeInfoIdParam = await ssm.getParameter({
50
+ Name: hostedZoneParameterName
51
+ });
52
+ const recordSetCreationResponseChangeInfoId = recordSetCreationResponseChangeInfoIdParam.Parameter?.Value;
53
+ log(`got R53 change info id: ${recordSetCreationResponseChangeInfoId} for event type ${event.RequestType}`);
54
+ log({
55
+ msg: "event",
56
+ event
57
+ });
58
+ switch (event.RequestType) {
59
+ case "Create":
60
+ log("waiting for DNS to propagate");
61
+ try {
62
+ const res = await (0, import_client_route_53.waitUntilResourceRecordSetsChanged)({
63
+ client: route53,
64
+ minDelay: 2,
65
+ maxWaitTime: 4
66
+ }, {
67
+ Id: recordSetCreationResponseChangeInfoId
68
+ });
69
+ switch (res.state) {
70
+ case "SUCCESS":
71
+ log(`DNS propagated with status '${res.state}'`);
72
+ return { IsComplete: true };
73
+ case "RETRY":
74
+ log(`DNS propagation not in sync yet. Has status '${res.state}'`);
75
+ return { IsComplete: false };
76
+ case "ABORTED":
77
+ case "FAILURE":
78
+ case "TIMEOUT":
79
+ log(`DNS propagation state failed '${res.state}'`);
80
+ return { IsComplete: false };
81
+ default:
82
+ log(`DNS propagation state unknow '${res.state}'`);
83
+ return { IsComplete: false };
84
+ }
85
+ } catch (e) {
86
+ log(`DNS propagation errored. Has message ${e}`);
87
+ return { IsComplete: false };
88
+ }
89
+ case "Update":
90
+ case "Delete":
91
+ return {
92
+ IsComplete: true
93
+ };
94
+ }
95
+ }
96
+ function log(msg) {
97
+ console.log(JSON.stringify(msg));
98
+ }
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ PROP_DOMAIN,
102
+ PROP_PARENT_HOSTED_ZONE_ID,
103
+ PROP_R53_HANGEINFO_ID_PARAMETER_NAME,
104
+ PROP_SUB_DOMAIN,
105
+ handler
106
+ });
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/rootmail-autowire-dns.on-event-handler.ts
21
+ var rootmail_autowire_dns_on_event_handler_exports = {};
22
+ __export(rootmail_autowire_dns_on_event_handler_exports, {
23
+ PROP_DOMAIN: () => PROP_DOMAIN,
24
+ PROP_HOSTED_ZONE_PARAMETER_NAME: () => PROP_HOSTED_ZONE_PARAMETER_NAME,
25
+ PROP_PARENT_HOSTED_ZONE_ID: () => PROP_PARENT_HOSTED_ZONE_ID,
26
+ PROP_R53_CHANGEINFO_ID_PARAMETER_NAME: () => PROP_R53_CHANGEINFO_ID_PARAMETER_NAME,
27
+ PROP_SUB_DOMAIN: () => PROP_SUB_DOMAIN,
28
+ handler: () => handler
29
+ });
30
+ module.exports = __toCommonJS(rootmail_autowire_dns_on_event_handler_exports);
31
+ var import_client_route_53 = require("@aws-sdk/client-route-53");
32
+ var import_client_ssm = require("@aws-sdk/client-ssm");
33
+ var PROP_DOMAIN = "Domain";
34
+ var PROP_SUB_DOMAIN = "Subdomain";
35
+ var PROP_PARENT_HOSTED_ZONE_ID = "ParentHostedZoneId";
36
+ var PROP_HOSTED_ZONE_PARAMETER_NAME = "HostedZoneParameterName";
37
+ var PROP_R53_CHANGEINFO_ID_PARAMETER_NAME = "R53ChangeInfoIdParameterName";
38
+ var route53 = new import_client_route_53.Route53();
39
+ var ssm = new import_client_ssm.SSM();
40
+ async function handler(event) {
41
+ const domain = event.ResourceProperties[PROP_DOMAIN];
42
+ const parentHostedZoneId = event.ResourceProperties[PROP_PARENT_HOSTED_ZONE_ID];
43
+ if (parentHostedZoneId === void 0 || parentHostedZoneId.trim().length === 0) {
44
+ switch (event.RequestType) {
45
+ case "Create":
46
+ log(`${event.RequestType}: Autowire DNS is disabled for '${domain}'. Skipping. PhysicalResourceId: ${event.RequestId}`);
47
+ return {
48
+ PhysicalResourceId: event.RequestId
49
+ };
50
+ case "Update":
51
+ case "Delete":
52
+ log(`${event.RequestType}: Autowire DNS is disabled for '${domain}'. Skipping. PhysicalResourceId: ${event.PhysicalResourceId}`);
53
+ return {
54
+ PhysicalResourceId: event.PhysicalResourceId
55
+ };
56
+ }
57
+ }
58
+ const subdomain = event.ResourceProperties[PROP_SUB_DOMAIN];
59
+ const hostedZoneParameterName = event.ResourceProperties[PROP_HOSTED_ZONE_PARAMETER_NAME];
60
+ const r53ChangeInfoIdParameterName = event.ResourceProperties[PROP_R53_CHANGEINFO_ID_PARAMETER_NAME];
61
+ switch (event.RequestType) {
62
+ case "Create":
63
+ const hostedZoneNameServerParameterResponse = await ssm.getParameter({
64
+ Name: hostedZoneParameterName
65
+ });
66
+ const hostedZoneNameServersAsString = hostedZoneNameServerParameterResponse.Parameter?.Value;
67
+ log({
68
+ event: hostedZoneNameServersAsString,
69
+ level: "debug"
70
+ });
71
+ if (hostedZoneNameServersAsString === void 0 || hostedZoneNameServersAsString === "") {
72
+ throw new Error(`hosted zone name servers not found or empty in parameter store for ${domain}: ${hostedZoneNameServersAsString}`);
73
+ }
74
+ const hostedZoneNameServers = hostedZoneNameServersAsString?.split(",");
75
+ if (hostedZoneNameServers.length !== 4) {
76
+ throw new Error(`expected exactly 4 hosted zone name servers for ${domain}. Got ${hostedZoneNameServers.length}: ${hostedZoneNameServers}`);
77
+ }
78
+ const hostedZoneResponse = await route53.listHostedZonesByName({
79
+ DNSName: domain
80
+ });
81
+ if (hostedZoneResponse.HostedZones === void 0 || hostedZoneResponse.HostedZones?.length === 0) {
82
+ log({
83
+ event: hostedZoneResponse,
84
+ level: "debug"
85
+ });
86
+ throw new Error(`expected to find at least one hosted zone for ${domain}`);
87
+ }
88
+ const filteredHostedZones = hostedZoneResponse.HostedZones?.filter((hostedZone) => {
89
+ return hostedZone.Id === `/hostedzone/${parentHostedZoneId}`;
90
+ });
91
+ if (filteredHostedZones.length !== 1) {
92
+ log({
93
+ event: hostedZoneResponse,
94
+ level: "debug"
95
+ });
96
+ throw new Error(`expected to find & filter exactly 1 hosted zone for ${domain}. Got ${filteredHostedZones.length}`);
97
+ }
98
+ const listResourceRecordSetsResponse = await route53.listResourceRecordSets({
99
+ // remove the prefix for using it as parameter
100
+ HostedZoneId: parentHostedZoneId.replace("/hostedzone/", "")
101
+ });
102
+ if (listResourceRecordSetsResponse.ResourceRecordSets === void 0) {
103
+ log({
104
+ event: listResourceRecordSetsResponse,
105
+ level: "debug"
106
+ });
107
+ throw new Error(`expected to find at least one resource record set for ${domain}`);
108
+ }
109
+ const existingNSRecordSet = listResourceRecordSetsResponse.ResourceRecordSets?.find((recordSet) => {
110
+ return recordSet.Name === `${subdomain}.${domain}.` && recordSet.Type === "NS";
111
+ });
112
+ if (existingNSRecordSet !== void 0) {
113
+ log({
114
+ event: existingNSRecordSet,
115
+ level: "debug"
116
+ });
117
+ log(`NS record for Name '${subdomain}.${domain}' and type NS already exists. Skipping.`);
118
+ return {
119
+ PhysicalResourceId: event.RequestId
120
+ };
121
+ }
122
+ log(`NS record for Name '${subdomain}.${domain}' and type NS does not exist. Creating.`);
123
+ const recordSetCreationResponse = await route53.changeResourceRecordSets({
124
+ HostedZoneId: parentHostedZoneId,
125
+ ChangeBatch: {
126
+ Comment: "rootmail-autowire-dns",
127
+ Changes: [
128
+ {
129
+ Action: "CREATE",
130
+ ResourceRecordSet: {
131
+ Name: `${subdomain}.${domain}`,
132
+ Type: "NS",
133
+ TTL: 60,
134
+ ResourceRecords: [
135
+ // are always 4
136
+ { Value: hostedZoneNameServers[0] },
137
+ { Value: hostedZoneNameServers[1] },
138
+ { Value: hostedZoneNameServers[2] },
139
+ { Value: hostedZoneNameServers[3] }
140
+ ]
141
+ }
142
+ }
143
+ ]
144
+ }
145
+ });
146
+ await ssm.putParameter({
147
+ Name: r53ChangeInfoIdParameterName,
148
+ Value: recordSetCreationResponse.ChangeInfo.Id,
149
+ Overwrite: true
150
+ });
151
+ return {
152
+ PhysicalResourceId: event.RequestId
153
+ };
154
+ case "Update":
155
+ log(`Skipping update for NS record for Name '${subdomain}.${domain}'`);
156
+ return {
157
+ PhysicalResourceId: event.PhysicalResourceId
158
+ };
159
+ case "Delete":
160
+ log(`Deleting NS record for Name '${subdomain}.${domain}' in the hosted zone with ID ${parentHostedZoneId}`);
161
+ const recordName = `${subdomain}.${domain}`;
162
+ try {
163
+ let nextRecordName;
164
+ let isRecordDeleted = false;
165
+ do {
166
+ const recordsResponse = await route53.listResourceRecordSets({
167
+ HostedZoneId: parentHostedZoneId,
168
+ StartRecordName: nextRecordName
169
+ });
170
+ for (const recordSet of recordsResponse.ResourceRecordSets || []) {
171
+ if (recordSet.Name === `${recordName}.` && recordSet.Type === "NS") {
172
+ console.log(`Deleting record: ${recordSet.Name} ${recordSet.Type}`);
173
+ await route53.changeResourceRecordSets({
174
+ HostedZoneId: parentHostedZoneId,
175
+ ChangeBatch: {
176
+ Changes: [
177
+ {
178
+ Action: "DELETE",
179
+ ResourceRecordSet: recordSet
180
+ }
181
+ ]
182
+ }
183
+ });
184
+ console.log(`Deleted record: ${recordSet.Name} ${recordSet.Type}. Stopping here.`);
185
+ isRecordDeleted = true;
186
+ break;
187
+ }
188
+ }
189
+ nextRecordName = recordsResponse.NextRecordName;
190
+ if (isRecordDeleted) {
191
+ console.log(`Record deleted: ${recordName} type 'NS'. Quitting.`);
192
+ break;
193
+ }
194
+ } while (nextRecordName);
195
+ } catch (err) {
196
+ console.log(`Error deleting records: ${err}`);
197
+ throw err;
198
+ }
199
+ return {
200
+ PhysicalResourceId: event.PhysicalResourceId
201
+ };
202
+ }
203
+ }
204
+ function log(msg) {
205
+ console.log(JSON.stringify(msg));
206
+ }
207
+ // Annotate the CommonJS export names for ESM import in node:
208
+ 0 && (module.exports = {
209
+ PROP_DOMAIN,
210
+ PROP_HOSTED_ZONE_PARAMETER_NAME,
211
+ PROP_PARENT_HOSTED_ZONE_ID,
212
+ PROP_R53_CHANGEINFO_ID_PARAMETER_NAME,
213
+ PROP_SUB_DOMAIN,
214
+ handler
215
+ });