Trigger an Action from an Event Notification
    • Dark
      Light

    Trigger an Action from an Event Notification

    • Dark
      Light

    Article Summary

    The Webhook.site is convenient because you can use it to receive and display HTTP messages without creating an account, but it is somewhat limited. This tutorial uses Pipedream, a workflow automation platform that is similar to IFTTT and Zapier, to deploy the webhook endpoint, run JavaScript code to validate the message signature, and append a row to a Google Sheet that contains fields from the Event Notification message.

    After you create a Pipedream account, you can use the code from this tutorial, and the Python code in the AWS Lambda tutorial, as the basis to validate Backblaze B2 Event Notification message signatures in your integrations.

    Note
    This feature is currently in private preview. For information about enabling this feature, see Automate Your Data Workflows With Backblaze B2 Event Notifications.

    Retrieve the Event Notification Rule Signing Secret

    You can retrieve the signing secret that Backblaze B2 created when you saved the rule.

    Since you can trigger an action from each Event Notification message, you should ensure that those messages really do come from Backblaze B2 and that they have not been tampered with in transit. Each message contains a signature that is sent in the x-bz-event-notification-signature HTTP header. The signature is a hex-encoded hash-based message authentication code (HMAC) that is computed from the message payload and a signing secret that Backblaze B2 generates when you create a rule. You can retrieve the signing secret using either the b2_get_bucket_notification_rules API or the Backblaze web UI. This tutorial uses the Backblaze web UI.

    1. Sign in to your Backblaze account.
    2. In the left navigation menu under B2 Cloud Storage, click Buckets.
    3. Click the Event Notifications link for your bucket.
    4. In the Event Notifications dialog next to Secret, click(copy).
    5. Save the secret value for use in a later step.

    Validate the Event Notification Message Signature

    You can validate a message signature to verify that the message was sent by Backblaze B2, and it was not tampered with in transit.

    Before you begin: Create a Pipedream account using either a Google or GitHub account or email and password.

    1. Sign in to your Pipedream account.
    2. Create a project.
      1. Click Create Project.
      2. Enter a name for your project.
      3. Click Create Project.
    3. Create a workflow.
      1. In your newly created project, click New.
      2. Select Workflow.
      3. Enter a name for your workflow.
        Leave all other fields as their default values.
      4. Click Create Workflow.
    4. Select a trigger to fire the workflow to build a webhook endpoint that receives HTTP POST requests.
      1. Click New HTTP / Webhook Requests.
      2. In the Event Data menu, select Raw Request to enable your workflow to access the raw request payload to validate the message signature.
      3. In the HTTP Response menu, select Return a custom response from your workflow.
        Leave all other fields as their default values.
      4. Click Save and continue.
      5. In the Select Event tab, click(copy) next to your unique URL.

    Leave the Pipedream browser tab open.

    Add a Target URL

    1. In a new tab, sign in to your Backblaze account.
    2. In the left navigation menu under B2 Cloud Storage, click Buckets.
    3. Click the Event Notifications link for your bucket.
    4. In the Event Notifications dialog, click(kebab icon) and click Edit.
      You can include each event type in only one event notification rule, so you cannot keep the existing object creation rule and add a new one for the same event types.
    5. Paste the Pipedream URL into the Target URL field, and click Test Rule.
    6. Click Save Rule.

    An Event Notification is sent to Pipedream.

    View the Event Notification

    1. In Pipedream, select the new POST event in the Select Event menu.
      The Event Notification message payload is displayed.
    2. Open the headers element to inspect it. The headers element is an array of strings with header names that alternate with their values including X-Bz-Event-Notification-Signature.
    3. Click Continue.

    Add JavaScript to Validate the Message Signature

    1. In Pipedream, click Run custom code.
    2. Select all of the code in the new step, delete it, and paste in the following JavaScript:
      Click here for JavaScript code.


      import { createHmac } from 'node:crypto';
      
      export default defineComponent({
        props: {
          // Paste the signing secret into the Pipedream web UI
          signingSecret: {
            type: "string",
            secret: true,
            label: "HMAC-SHA-256 Signing Secret",
            description:
              "Your event notification rule webhook signing key, available in the " +
              "Web UI and returned from b2_get_bucket_notification_rules as " + 
              "hmacSha256SigningSecret.",
          },
        },
        methods: {
          // The code requires that 'Event Data' is set to 'Raw request'. This causes
          // headers to be encoded as an array of strings with even entries being the 
          // header keys and odd entries being the value of the header referred to by 
          // the previous entry.
          //
          // Create an object containing a mapping of lowercased keys to the 
          // appropriate values.
          createHeaderMap(headerArray) {
            const headerMap = {};
      
            for (let i = 0; i < headerArray.length; i+=2) {
              headerMap[headerArray[i].toLowerCase()] = headerArray[i+1];
            }
      
            return headerMap;
          },
          // Helper method to log an error, send the HTTP response, and exit the flow
          async handleError(status, message, detail, $) {
            console.error(`${message}: ${detail}`);
            await $.respond({status: status, body: message});
            return $.flow.exit(message);
          },
        },
        // This is the entry point for the step
        // See https://pipedream.com/docs/code/nodejs/#adding-a-code-step
        async run({steps, $}) {
          const event = steps.trigger.event;
      
          // event.headers is an array with alternating header names and values
          // It's much easier to work with as a map!
          const headers = this.createHeaderMap(event.headers);
      
          if ('x-bz-event-notification-signature' in headers) {
            // Verify that signature has form "v1=2c8...231"
            const signature = headers['x-bz-event-notification-signature'];
            const pair = signature.split('=');
            if (!pair || pair.length !== 2) {
              return this.handleError(401, 'Invalid signature format', signature, $);
            }
            const version = pair[0];
            if (version !== 'v1') {
              return this.handleError(401, 'Invalid signature version', version, $);
            }
      
            // Now calculate the HMAC and compare it with the one sent in the header
            const receivedSig = pair[1];
            const calculatedSig = createHmac('sha256', this.signingSecret)
              .update(event.body)
              .digest('hex');
            if (receivedSig !== calculatedSig) {
              return this.handleError(401, 
                'Invalid signature', 
                `Received ${receivedSig}; calculated ${calculatedSig}`, 
                $
              );
            }
          } else {
            return this.handleError(401, 'Missing signature header', '', $);
          }
      
          // Success!
          console.log('Signature is valid');
      
          // Parse the raw message body so later steps can access the fields
          try {
            const eventData = JSON.parse(event.body);
      
            await $.respond({
              immediate: true,
              status: 200, 
              body: 'OK'
            });
      
            // Return the event for use by later steps
            return eventData;
          } catch (e) {
            return this.handleError(400, 'Invalid JSON in message payload', e, $);
          }
        },
      })
      You can use this code as the basis for your own integrations. The HMAC-SHA256 calculation is very straightforward.
    3. Click Refresh fields so that Pipedream parses the code and displays a field to enter the signing secret.
    4. Paste the secret value that you saved earlier in the HMAC-SHA-256 Signing Secret field.
    5. Click Test to run the Node.js code on the test message that Pipedream received earlier.
      The test fails, however, this failure is expected. For this release of Event Notifications, Backblaze B2 uses a dummy secret to sign the test event. Since the HMAC in the test event is signed with the dummy secret, it does not match the one that is generated by the Node.js code using the real signing secret. In the future, the real signing secret will be used to sign the test event.
    6. Click Deploy.

    Send the Notification

    1. In your Backblaze tab, upload another file to your bucket.
      A notification message is sent to the workflow.
    2. In your Pipedream tab, click the new event to see details.
    3. Open the body element to see the Event Notification message payload.

    The code step that the workflow was successfully run. A response was generated with a body of “OK” and a status of 200. The signature was valid, so the code verified that the message was signed by Backblaze B2 and was not tampered with in transit.

    Perform an Action in Response to an Event Notification

    Pipedream can tell the workflow to perform an action that is triggered by each event. This tutorial uses Pipedream to add a row to a spreadsheet in Google Sheets.

    1. Sign in to Google, and go to https://sheet.new/.
    2. Enter a meaningful name in the spreadsheet so that it is easy to select in another step.
    3. Paste the following headers in the first row of the sheet:
      • Event Timestamp
      • Event Type
      • Object Name
      • Object Size
      • Object Version ID
    4. In Pipedream, click Edit in the upper-right corner of the page to return to the workflow builder.
    5. Click(add) under the "code" step.
    6. Click Google Sheets.
      If you do not see Google Sheets listed among the apps, enter Google Sheets into the ‘Search for an app…’ field.
    7. Click Add Single Row.
    8. Connect your Google Sheets account to Pipedream.
      1. Click Connect a Google Sheets account, select your Google account, and give Pipedream permission to access your Google Drive files.
      2. Select the spreadsheet you just created.
      3. Select the sheet name.
      4. Select Yes in the Does the first row of the sheet have headers? field.
      5. For each of the headers, click the dropdown menu, scroll past the raw message body, and select the relevant element under steps.code.$return_value.events[0].
        When complete, the step dialog contains expressions for each of the elements.
      6. Click Test.
        A row is added to the spreadsheet. Google Sheets does not always automatically update as the row is added. You may need to refresh the page.
    9. Click Deploy to save the new action.

    If you upload more files to your Backblaze B2 bucket, more rows are added to the Google Sheets. You may need to refresh the page to see the new rows.

    You can experiment more with Pipedream. You might want to run custom code in a new step, send a Slack message for each event, or even send SMS messages using Twilio.


    Was this article helpful?