Skip to content

Instantly share code, notes, and snippets.

@armiiller
armiiller / stripe_subscription_update.rb
Created September 7, 2022 16:29 — forked from palkan/example.rb
pattern_matching_joe.rb
require 'active_support/core_ext/hash/indifferent_access'
def send_admin_notification(changes = previous_changes)
case changes
in ends_at: [Time, _]
:resubscribed
in ends_at: [nil, Time]
:churned
in processor_plan: [nil, String]
:subscribed
$now:
timezone: "America/Chicago"
format: "MM-DD"
$in:
- "01-01" # New Years
- "12-25" # Christmas
# ...
// Verify this actually came from our vendor
const signature = _.toString(req.headers['x-${BRAND}-signature']);
const timestamp = _.toString(req.headers['x-${BRAND}-timestamp']);
if(!signature || !timestamp || !_.parseInt(timestamp) || !moment.unix(_.parseInt(timestamp)).isBetween(moment().add(-5, 'm'), moment().add(1, 'm'))){
res.status(httpStatusCodes.BAD_REQUEST).send();
return;
}
// The initial required fields are there and they are within the time flex range, compute the expected hash
const hmac = crypto.createHmac('sha256', config.SIGNING_SECRET);
# A webhook signing algorythim, generally based off slacks https://api.slack.com/authentication/verifying-requests-from-slack
# I think I used this as the template: https://github.com/slack-ruby/slack-ruby-client/blob/master/lib/slack/events/request.rb#L51
# sign_and_send is what is being sent by the service providing the outgoing webhook service
# verify_and_process is what a recieving server would to to process the incoming webhook, you can also see a nodejs implementation here https://gist.github.com/armiiller/72e4729372036cd43536f4f799dd2b22
BRAND = "acme-inc" # TODO, your brand
def sign_and_send
# sign the request with the customers auth token
# the customers auth token is a shared secret, you can use a has_secure_token on the model
{{#if ctx.alert.meta.incident}}
[{{ctx.alert.meta.incident_severity}}] Incident #{{ctx.alert.tinyId}} - {{{ctx.alert.meta.incident_message}}} -{{{sanitize ctx.alert.title}}}
{{else}}
Alert #{{ctx.alert.tinyId}} {{{sanitize ctx.alert.title}}}
{{/if}}
{{#if ctx.bridge}}
{{#if ctx.bridge.access_code}}{{ctx.app.bridge_phone}},,{{buckjoin ctx.bridge.access_code 3 "-"}}#{{/if}}
{{#if ctx.bridge.url}}{{{ctx.bridge.url}}}{{/if}} {{#if ctx.bridge.phone}}{{{ctx.bridge.phone}}}{{/if}}
{{/if}}
{{#if ctx.alert.meta.incident}}
☢️ Incident #{{ctx.alert.tinyId}} [{{ctx.alert.meta.incident_severity}}] {{{sanitize ctx.alert.title}}}
{{else}}
� Alert #{{ctx.alert.tinyId}} {{{sanitize ctx.alert.title}}}
{{/if}}
{{#if ctx.alert.meta.incident}}
☢️ Incident #{{ctx.alert.tinyId}} [{{ctx.alert.meta.incident_severity}}] {{{sanitize ctx.alert.title}}}
{{else}}
� Alert #{{ctx.alert.tinyId}} {{{sanitize ctx.alert.title}}}
{{/if}}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="x-apple-disable-message-reformatting" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<style type="text/css" rel="stylesheet" media="all">
/* Base ------------------------------ */
{{#if ctx.alert.meta.incident}}
[{{ctx.alert.meta.incident_severity}}] Incident #{{ctx.alert.tinyId}}
{{{ctx.alert.meta.incident_message}}}
{{{sanitize ctx.alert.title}}}
{{else}}
Alert #{{ctx.alert.tinyId}} {{{sanitize ctx.alert.title}}}
{{/if}}
{{#if (and ctx.bridge (or ctx.bridge.phone (eq ctx.bridge.host "pagertree")))}}
{{#if ctx.alert.meta.incident}}Incident{{else}}Alert{{/if}} {{ctx.alert.tinyId}}. {{#if ctx.alert.meta.incident}}{{ctx.alert.meta.incident_severity}}. {{{ctx.alert.meta.incident_message}}}.{{/if}}{{{sanitize ctx.alert.title}}}.
Push {{default (get "account.notification_templates.alert_alert.voice.acknowledge" ctx) 1}} to acknowledge or {{default (get "account.notification_templates.alert_alert.voice.reject" ctx) 2}} to reject.