auths
objectreturn
or this.key = 'value'
, pass input data to your code viaparams
, and maintain state across executions with$checkpoint.async
(event, steps) => {
}
const crypto = require("crypto")
const axios = require('axios')
const AWS = require("aws-sdk")
// Confirm the presence of appropriate env vars, exiting if absent
const {
DDB_KMS_AWS_ACCESS_KEY_ID,
DDB_KMS_AWS_SECRET_ACCESS_KEY,
USER_APP_AWS_REGION,
USER_APP_DDB_TABLE
} = process.env
if (!DDB_KMS_AWS_ACCESS_KEY_ID) {
$end("No DDB_KMS_AWS_ACCESS_KEY_ID environment variable defined")
}
if (!DDB_KMS_AWS_SECRET_ACCESS_KEY) {
$end("No DDB_KMS_AWS_SECRET_ACCESS_KEY environment variable defined")
}
if (!USER_APP_AWS_REGION) {
$end("No USER_APP_AWS_REGION environment variable defined")
}
if (!USER_APP_DDB_TABLE) {
$end("No USER_APP_DDB_TABLE environment variable defined")
}
// Initialize AWS clients
const kmsClient = new AWS.KMS({
accessKeyId: DDB_KMS_AWS_ACCESS_KEY_ID,
secretAccessKey: DDB_KMS_AWS_SECRET_ACCESS_KEY,
region: USER_APP_AWS_REGION,
})
const dynamoDocClient = new AWS.DynamoDB.DocumentClient({
accessKeyId: DDB_KMS_AWS_ACCESS_KEY_ID,
secretAccessKey: DDB_KMS_AWS_SECRET_ACCESS_KEY,
region: USER_APP_AWS_REGION,
})
// $event.body contains the payload of the HTTP request sent to this pipeline.
// userId and app are both contained in the payload, so we can assign variables
// from $event.body accordingly
const { userId, app } = $event.body
// Retrieve the data from Dynamo and decrypt it
const { Item } = await dynamoDocClient
.get({
TableName: USER_APP_DDB_TABLE,
Key: {
userId,
app
}
})
.promise()
if (!Item) {
$end(`No item found in Dynamo for user ${userId}, app ${app}`)
}
// Now we define a couple of helper functions for decryption to make the process
// clear. Since the data was originally encrypted with the data key and salt,
// we'll need to use both of these to decrypt the value using the master key
async function decryptWithMasterKey(CiphertextBlob) {
const decryptedDataKey = await kmsClient
.decrypt({
CiphertextBlob
})
.promise();
return decryptedDataKey.Plaintext;
}
async function decrypt(content, encryptedDataKey, salt) {
const decryptedDataKey = await decryptWithMasterKey(encryptedDataKey);
const decryptor = crypto.createDecipheriv(
"AES-256-CBC",
decryptedDataKey,
salt
);
decryptor.write(content);
decryptor.end();
return decryptor.read().toString("utf8");
}
// Everything up to this point has been app-agnostic. Now, we decrypt
// specific attributes from the Dynamo object and set them as properties
// of $event we can reference later
switch(app) {
case 'slack':
const slackWebhookURL = await decrypt(
Item.encryptedWebhookURL,
Item.encryptedDataKey,
Item.salt
)
// Send a message to the Slack webhook URL retrieved from Dynamo
const { status, statusText, headers } = await axios.post(slackWebhookURL, {
"text": ":tada: Test Slack Message!"
})
// Store the response so we can save to S3 for auditing
$event.resp = {
status,
statusText,
headers,
}
break
default:
$end("App not handled in switch statement")
}