This repository has been archived by the owner on Apr 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.js
138 lines (113 loc) · 3.57 KB
/
index.js
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
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
'use strict'
const crypto = require('crypto')
const qs = require('qs')
const Promise = require('bluebird')
const AWS = require('aws-sdk')
const P = require('bluebird')
AWS.config.setPromisesDependency(P)
const {
AUTH, PROVIDER, SQS_REGION,
BOUNCE_QUEUE_URL, COMPLAINT_QUEUE_URL, DELIVERY_QUEUE_URL
} = process.env
const region = SQS_REGION || 'us-east-1'
if (! AUTH || ! PROVIDER || ! BOUNCE_QUEUE_URL || ! COMPLAINT_QUEUE_URL || ! DELIVERY_QUEUE_URL) {
throw new Error('Missing config')
}
const ACCEPTED_PROVIDERS = [
'sendgrid',
'socketlabs'
]
if (! ACCEPTED_PROVIDERS.includes(PROVIDER)) {
throw new Error(`Only the following providers are supported: ${ACCEPTED_PROVIDERS.join(', ')}`)
}
const provider = require(`./${PROVIDER}`)
const AUTH_HASH = createHash(AUTH).split('')
const QUEUES = {
Bounce: BOUNCE_QUEUE_URL,
Complaint: COMPLAINT_QUEUE_URL,
Delivery: DELIVERY_QUEUE_URL
}
const SQS = new AWS.SQS({ region })
module.exports = { main }
async function main (data) {
// If there's a body, it's a request from the API gateway
if (data.body) {
// Requests from the API gateway must be authenticated
if (! data.queryStringParameters || ! authenticate(data.queryStringParameters.auth)) {
const errorResponse = {
error: 'Unauthorized',
errno: 999,
code: 401,
message: 'Request must provide a valid auth query param.'
}
return {
statusCode: 401,
body: JSON.stringify(errorResponse),
isBase64Encoded: false
}
}
if (data.headers && data.headers['Content-Type'] === 'application/x-www-form-urlencoded') {
data = qs.parse(data.body)
} else {
data = JSON.parse(data.body)
}
}
if (! Array.isArray(data)) {
data = [ data ]
}
if (PROVIDER === 'socketlabs' && provider.shouldValidate(data[0])) {
return provider.validationResponse()
}
const results = await processEvents(data)
let response = {
result: `Processed ${results.length} events`
}
response = provider.annotate(response)
return {
statusCode: 200,
body: JSON.stringify(response),
isBase64Encoded: false
}
}
function authenticate (auth) {
const authHash = createHash(auth)
return AUTH_HASH
.reduce((equal, char, index) => equal && char === authHash[index], true)
}
function createHash (value) {
const hash = crypto.createHash('sha256')
hash.update(value)
return hash.digest('base64')
}
async function processEvents (events) {
return Promise.all(
events.map(provider.marshallEvent)
.filter(event => !! event)
.map(sendEvent)
)
}
function sendEvent (event) {
// The message we send to SQS has to have this structure to
// mimic exactly the message SNS sends to it in the SES -> SNS -> SQS flow.
// See documentation: https://docs.aws.amazon.com/sns/latest/dg/SendMessageToSQS.html
const message = {
Message: JSON.stringify(event),
Type: 'Notification',
Timestamp: event.mail && event.mail.timestamp ? event.mail.timestamp : new Date().toISOString()
}
const queueUrl = QUEUES[event.notificationType]
const params = {
QueueUrl: queueUrl,
MessageBody: JSON.stringify(message)
}
return SQS.sendMessage(params).promise()
.then(() => console.log('Sent:', event.notificationType))
.catch(error => {
console.error('Failed to send event:', event)
console.error(error && error.stack)
throw error
})
}