Validating SNS message in NodeJS, promisified

in aws programming

Validating SNS message in NodeJS, promisified

If you want to subscribe to an SNS topic, it's a good idea to validate if the received request is an actual valid SNS message. AWS has a (rather old) NPM package for validation. To prevent callback hell, I've created a convenience function that validates the message using the provided signature.

The function uses the sns-validator package under the hood, which:

After this validation, you can be sure that:

You still don't know if it was provided by the topic you're actually subscribed to/wanting to subscribe to. I'd strongly recommend at least checking the topic ARN against an allowlist before doing something with the payload.

The function expects an SNS message delivered via http, formatted like this:

{
  "Type" : "Notification",
  "MessageId" : "da41e39f-ea4d-435a-b922-c6aae3915ebe",
  "TopicArn" : "arn:aws:sns:us-west-2:123456789012:MyTopic",
  "Subject" : "test",
  "Message" : "test message",
  "Timestamp" : "2012-04-25T21:49:25.719Z",
  "SignatureVersion" : "1",
  "Signature" : "EXAMPLElDMXvB8r9R83tGoNn0ecwd5UjllzsvSvbItzfaMpN2nk5HVSw7XnOn/49IkxDKz8YrlH2qJXj2iZB0Zo2O71c4qQk1fMUDi3LGpij7RCW7AW9vYYsSqIKRnFS94ilu7NFhUzLiieYr4BKHpdTmdD6c0esKEYBpabxDSc=",
  "SigningCertURL" : "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-f3ecfb7224c7233fe7bb5f59f96de52f.pem",
   "UnsubscribeURL" : "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:123456789012:MyTopic:2bcfbf39-05c3-41de-beaa-fcfcc21c8f55"
}

source

Besides validating if the message is valid, the function will subscribe to the topic if the provided message is a 'SubscriptionConfirmation' type notification. In all other cases it just returns the original message.

import * as https from 'https';
import MessageValidator from 'sns-validator';

async function validateMessage(message: any): Promise<any> {
  const validator = new MessageValidator();
  return new Promise((resolve, reject) => {
    validator.validate(message, (err, aMessage) => {
      if (err) {
        return reject(err);
      }
      if (aMessage?.Type === 'SubscriptionConfirmation' && aMessage.SubscribeURL) {
        https.get(aMessage.SubscribeURL, function (_res) {
          // You have confirmed your endpoint subscription
        });
      }
      resolve(aMessage);
    });
  });
}