bullet_train-outgoing_webhooks 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/app/assets/config/{bullet_train_outgoing_webhooks_web_manifest.js → bullet_train_outgoing_webhooks_manifest.js} +0 -0
  4. data/app/controllers/account/webhooks/outgoing/endpoints_controller.rb +4 -3
  5. data/app/controllers/api/v1/webhooks/outgoing/deliveries_endpoint.rb +63 -0
  6. data/app/controllers/api/v1/webhooks/outgoing/delivery_attempts_endpoint.rb +65 -0
  7. data/app/controllers/api/v1/webhooks/outgoing/endpoints_endpoint.rb +119 -0
  8. data/app/jobs/webhooks/outgoing/delivery_job.rb +7 -0
  9. data/app/jobs/webhooks/outgoing/generate_job.rb +7 -0
  10. data/app/models/concerns/webhooks/outgoing/delivery_attempt_support.rb +64 -0
  11. data/app/models/concerns/webhooks/outgoing/delivery_support.rb +66 -0
  12. data/app/models/concerns/webhooks/outgoing/endpoint_support.rb +37 -0
  13. data/app/models/concerns/webhooks/outgoing/event_support.rb +45 -0
  14. data/app/models/concerns/webhooks/outgoing/issuing_model.rb +67 -0
  15. data/app/models/concerns/webhooks/outgoing/team_support.rb +31 -0
  16. data/app/models/concerns/webhooks/outgoing/uri_filtering.rb +149 -0
  17. data/app/models/webhooks/outgoing/delivery.rb +20 -0
  18. data/app/models/webhooks/outgoing/delivery_attempt.rb +20 -0
  19. data/app/models/webhooks/outgoing/endpoint.rb +20 -0
  20. data/app/models/webhooks/outgoing/event.rb +3 -0
  21. data/app/models/webhooks/outgoing/event_type.rb +13 -0
  22. data/app/models/webhooks/outgoing.rb +5 -0
  23. data/app/models/webhooks.rb +5 -0
  24. data/app/serializers/api/v1/webhooks/outgoing/delivery_attempt_serializer.rb +16 -0
  25. data/app/serializers/api/v1/webhooks/outgoing/delivery_serializer.rb +14 -0
  26. data/app/serializers/api/v1/webhooks/outgoing/endpoint_serializer.rb +14 -0
  27. data/app/views/account/webhooks/outgoing/deliveries/_menu_item.html.erb +2 -2
  28. data/app/views/account/webhooks/outgoing/delivery_attempts/_menu_item.html.erb +2 -2
  29. data/app/views/account/webhooks/outgoing/endpoints/_breadcrumbs.html.erb +1 -1
  30. data/app/views/account/webhooks/outgoing/endpoints/_form.html.erb +2 -2
  31. data/app/views/account/webhooks/outgoing/endpoints/_index.html.erb +3 -3
  32. data/app/views/account/webhooks/outgoing/endpoints/_menu_item.html.erb +2 -2
  33. data/app/views/account/webhooks/outgoing/endpoints/show.html.erb +1 -1
  34. data/config/routes.rb +1 -1
  35. data/db/migrate/20180420013127_create_webhooks_outgoing_endpoints.rb +10 -0
  36. data/db/migrate/20180420013505_create_webhooks_outgoing_endpoint_event_types.rb +10 -0
  37. data/db/migrate/20180420013852_create_webhooks_outgoing_event_types.rb +9 -0
  38. data/db/migrate/20180420014623_create_webhooks_outgoing_events.rb +12 -0
  39. data/db/migrate/20180420021016_create_webhooks_outgoing_deliveries.rb +11 -0
  40. data/db/migrate/20180420022027_add_team_to_webhooks_outgoing_events.rb +5 -0
  41. data/db/migrate/20180420165345_create_webhooks_outgoing_delivery_attempts.rb +11 -0
  42. data/db/migrate/20180420172112_add_error_message_to_webhooks_outgoing_delivery_attempt.rb +6 -0
  43. data/db/migrate/20181012234232_add_name_to_webhooks_outgoing_endpoints.rb +5 -0
  44. data/db/migrate/20181013030208_add_delivered_at_to_webhooks_outgoing_deliveries.rb +5 -0
  45. data/db/migrate/20181013165056_add_uuid_to_webhooks_outgoing_events.rb +5 -0
  46. data/db/migrate/20181013174539_add_payload_to_webhooks_outgoing_events.rb +5 -0
  47. data/db/migrate/20181013192951_add_attempt_number_to_webhooks_outgoing_delivery_attempts.rb +5 -0
  48. data/db/migrate/20210805060451_change_body_to_data_on_webhooks_outgoing_events.rb +5 -0
  49. data/db/migrate/20211126230846_add_event_type_ids_to_webhooks_outgoing_endpoints.rb +5 -0
  50. data/db/migrate/20211126230847_migrate_event_type_ids_on_webhooks_outgoing_endpoints.rb +8 -0
  51. data/db/migrate/20211127013539_remove_event_type_from_webhooks_outgoing_events.rb +5 -0
  52. data/db/migrate/20211127013800_add_new_event_type_id_to_webhooks_outgoing_events.rb +5 -0
  53. data/db/migrate/20211127014001_migrate_event_types_on_webhooks_outgoing_events.rb +10 -0
  54. data/db/migrate/20211127015712_drop_webhooks_outgoing_endpoint_event_types.rb +9 -0
  55. data/db/migrate/20211127015713_drop_webhooks_outgoing_event_types.rb +9 -0
  56. data/lib/bullet_train/outgoing_webhooks/engine.rb +32 -0
  57. data/lib/bullet_train/outgoing_webhooks/version.rb +1 -1
  58. data/lib/bullet_train/outgoing_webhooks.rb +28 -3
  59. metadata +81 -8
@@ -0,0 +1,149 @@
1
+ require "resolv"
2
+ require "public_suffix"
3
+
4
+ module Webhooks::Outgoing::UriFiltering
5
+ extend ActiveSupport::Concern
6
+
7
+ # WEBHOOK SECURITY PRIMER
8
+ # =============================================================================
9
+ # Outgoing webhooks can be dangerous. By allowing your users to set
10
+ # up outgoing webhooks, you"re giving them permission to call arbitrary
11
+ # URLs from your server, including URLs that could represent resources
12
+ # internal to your company. Malicious actors can use this permission to
13
+ # examine your infrastructure, call internal APIs, and generally cause
14
+ # havok.
15
+
16
+ # This module attempts to block malicious actors with the following algorithm
17
+ # 1. Block anything but http and https requests
18
+ # 2. Block or allow defined hostnames, both regex and strings
19
+ # 3. Block if `custom_block_callback` returns true (args: self, uri)
20
+ # 4. Allow if `custom_allow_callback` returns true (args: self, uri)
21
+ # 5. Resolve the IP associated with the webhook"s host directly from
22
+ # the authoritative name server for the host"s domain. This IP
23
+ # is cached for the returned DNS TTL
24
+ # 6. Match the given IP against lists of allowed and blocked cidr ranges.
25
+ # The blocked list by default includes all of the defined private address
26
+ # ranges, localhost, the private IPv6 prefix, and the AWS metadata
27
+ # API endpoint.
28
+
29
+ # If at any point a URI is determined to be blocked we call `audit_callback`
30
+ # (args: self, uri) so it can be logged for auditing.
31
+
32
+ # We resolve the IP from the authoritative name server directly so we can avoid
33
+ # certain classes of DNS poisoning attacks.
34
+
35
+ # Users of this gem are _strongly_ enouraged to add additional cidr ranges
36
+ # and hostnames to the appropriate lists and/or implement `custom_block_callback`.
37
+ # At the very least you should add the public hostname that your
38
+ # application uses to the blocked_hostnames list.
39
+
40
+ class AllowedUriValidator < ActiveModel::EachValidator
41
+ def validate_each(record, attribute, value)
42
+ uri = URI.parse(value)
43
+ unless record.allowed_uri?(uri)
44
+ record.errors.add attribute, "is not an allowed uri"
45
+ end
46
+ end
47
+ end
48
+
49
+ def resolve_ip_from_authoritative(hostname)
50
+ begin
51
+ ip = IPAddr.new(hostname)
52
+ return ip.to_s
53
+ rescue IPAddr::InvalidAddressError
54
+ # this is fine, proceed with resolver path
55
+ end
56
+
57
+ cache_key = "#{cache_key_with_version}/uri_ip/#{Digest::SHA2.hexdigest(hostname)}"
58
+
59
+ cached = Rails.cache.read(cache_key)
60
+ if cached
61
+ return cached == "invalid" ? nil : cached
62
+ end
63
+
64
+ begin
65
+ # This is sort of a half-recursive DNS resolver.
66
+ # We can't implement a full recursive resolver using just Resolv::DNS so instead
67
+ # this asks a public cache for the NS record for the given domain. Then it asks
68
+ # the authoritative nameserver directly for the address and caches it according
69
+ # to the returned TTL.
70
+
71
+ config = Rails.configuration.outgoing_webhooks
72
+ ns_resolver = Resolv::DNS.new(nameserver: config[:public_resolvers])
73
+ ns_resolver.timeouts = 1
74
+
75
+ domain = PublicSuffix.domain(hostname)
76
+ authoritative = ns_resolver.getresource(domain, Resolv::DNS::Resource::IN::NS)
77
+
78
+ authoritative_resolver = Resolv::DNS.new(nameserver: [authoritative.name.to_s])
79
+ authoritative_resolver.timeouts = 1
80
+
81
+ resource = authoritative_resolver.getresource(hostname, Resolv::DNS::Resource::IN::A)
82
+ Rails.cache.write(cache_key, resource.address.to_s, expires_in: resource.ttl, race_condition_ttl: 5)
83
+ resource.address.to_s
84
+ rescue IPAddr::InvalidAddressError, ArgumentError # standard:disable Lint/ShadowedException
85
+ Rails.cache.write(cache_key, "invalid", expires_in: 10.minutes, race_condition_ttl: 5)
86
+ nil
87
+ end
88
+ end
89
+
90
+ def allowed_uri?(uri)
91
+ unless _allowed_uri?(uri)
92
+ config = Rails.configuration.outgoing_webhooks
93
+ if config[:audit_callback].present?
94
+ config[:audit_callback].call(self, uri)
95
+ end
96
+ return false
97
+ end
98
+
99
+ true
100
+ end
101
+
102
+ def _allowed_uri?(uri)
103
+ config = Rails.configuration.outgoing_webhooks
104
+ hostname = uri.hostname.downcase
105
+
106
+ return false unless config[:allowed_schemes].include?(uri.scheme)
107
+
108
+ config[:blocked_hostnames].each do |blocked|
109
+ if blocked.is_a?(Regexp)
110
+ return false if blocked.match?(hostname)
111
+ end
112
+
113
+ return false if blocked == hostname
114
+ end
115
+
116
+ config[:allowed_hostnames].each do |allowed|
117
+ if allowed.is_a?(Regexp)
118
+ return true if allowed.match?(hostname)
119
+ end
120
+
121
+ return true if allowed == hostname
122
+ end
123
+
124
+ if config[:custom_allow_callback].present?
125
+ return true if config[:custom_allow_callback].call(self, uri)
126
+ end
127
+
128
+ if config[:custom_block_callback].present?
129
+ return false if config[:custom_block_callback].call(self, uri)
130
+ end
131
+
132
+ resolved_ip = resolve_ip_from_authoritative(hostname)
133
+ return false if resolved_ip.nil?
134
+
135
+ begin
136
+ config[:allowed_cidrs].each do |cidr|
137
+ return true if IPAddr.new(cidr).include?(resolved_ip)
138
+ end
139
+
140
+ config[:blocked_cidrs].each do |cidr|
141
+ return false if IPAddr.new(cidr).include?(resolved_ip)
142
+ end
143
+ rescue IPAddr::InvalidAddressError
144
+ return false
145
+ end
146
+
147
+ true
148
+ end
149
+ end
@@ -0,0 +1,20 @@
1
+ class Webhooks::Outgoing::Delivery < BulletTrain::OutgoingWebhooks.base_class.constantize
2
+ include Webhooks::Outgoing::DeliverySupport
3
+ # 🚅 add concerns above.
4
+
5
+ # 🚅 add belongs_to associations above.
6
+
7
+ # 🚅 add has_many associations above.
8
+
9
+ # 🚅 add has_one associations above.
10
+
11
+ # 🚅 add scopes above.
12
+
13
+ # 🚅 add validations above.
14
+
15
+ # 🚅 add callbacks above.
16
+
17
+ # 🚅 add delegations above.
18
+
19
+ # 🚅 add methods above.
20
+ end
@@ -0,0 +1,20 @@
1
+ class Webhooks::Outgoing::DeliveryAttempt < BulletTrain::OutgoingWebhooks.base_class.constantize
2
+ include Webhooks::Outgoing::DeliveryAttemptSupport
3
+ # 🚅 add concerns above.
4
+
5
+ # 🚅 add belongs_to associations above.
6
+
7
+ # 🚅 add has_many associations above.
8
+
9
+ # 🚅 add has_one associations above.
10
+
11
+ # 🚅 add scopes above.
12
+
13
+ # 🚅 add validations above.
14
+
15
+ # 🚅 add callbacks above.
16
+
17
+ # 🚅 add delegations above.
18
+
19
+ # 🚅 add methods above.
20
+ end
@@ -0,0 +1,20 @@
1
+ class Webhooks::Outgoing::Endpoint < BulletTrain::OutgoingWebhooks.base_class.constantize
2
+ include Webhooks::Outgoing::EndpointSupport
3
+ # 🚅 add concerns above.
4
+
5
+ # 🚅 add belongs_to associations above.
6
+
7
+ # 🚅 add has_many associations above.
8
+
9
+ # 🚅 add has_one associations above.
10
+
11
+ # 🚅 add scopes above.
12
+
13
+ # 🚅 add validations above.
14
+
15
+ # 🚅 add callbacks above.
16
+
17
+ # 🚅 add delegations above.
18
+
19
+ # 🚅 add methods above.
20
+ end
@@ -0,0 +1,3 @@
1
+ class Webhooks::Outgoing::Event < BulletTrain::OutgoingWebhooks.base_class.constantize
2
+ include Webhooks::Outgoing::EventSupport
3
+ end
@@ -0,0 +1,13 @@
1
+ class Webhooks::Outgoing::EventType < ApplicationHash
2
+ self.data = YAML.load_file("config/models/webhooks/outgoing/event_types.yml").map do |topic, events|
3
+ events.map { |event| event == "crud" ? ["created", "updated", "deleted"] : event }.flatten.map { |event| {id: "#{topic}.#{event}"} }
4
+ end.flatten
5
+
6
+ def label_string
7
+ name
8
+ end
9
+
10
+ def name
11
+ id
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Webhooks::Outgoing
2
+ def self.table_name_prefix
3
+ "webhooks_outgoing_"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Webhooks
2
+ def self.table_name_prefix
3
+ "webhooks_"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ class Api::V1::Webhooks::Outgoing::DeliveryAttemptSerializer < Api::V1::ApplicationSerializer
2
+ set_type "webhooks/outgoing/delivery_attempt"
3
+
4
+ attributes :id,
5
+ :delivery_id,
6
+ :response_code,
7
+ :response_body,
8
+ :response_message,
9
+ :error_message,
10
+ :attempt_number,
11
+ # 🚅 super scaffolding will insert new fields above this line.
12
+ :created_at,
13
+ :updated_at
14
+
15
+ belongs_to :delivery, serializer: Api::V1::Webhooks::Outgoing::DeliverySerializer
16
+ end
@@ -0,0 +1,14 @@
1
+ class Api::V1::Webhooks::Outgoing::DeliverySerializer < Api::V1::ApplicationSerializer
2
+ set_type "webhooks/outgoing/delivery"
3
+
4
+ attributes :id,
5
+ :endpoint_id,
6
+ :event_id,
7
+ :endpoint_url,
8
+ :delivered_at,
9
+ # 🚅 super scaffolding will insert new fields above this line.
10
+ :created_at,
11
+ :updated_at
12
+
13
+ belongs_to :endpoint, serializer: Api::V1::Webhooks::Outgoing::EndpointSerializer
14
+ end
@@ -0,0 +1,14 @@
1
+ class Api::V1::Webhooks::Outgoing::EndpointSerializer < Api::V1::ApplicationSerializer
2
+ set_type "webhooks/outgoing/endpoint"
3
+
4
+ attributes :id,
5
+ :team_id,
6
+ :name,
7
+ :url,
8
+ :event_type_ids,
9
+ # 🚅 super scaffolding will insert new fields above this line.
10
+ :created_at,
11
+ :updated_at
12
+
13
+ belongs_to :team, serializer: Api::V1::TeamSerializer
14
+ end
@@ -1,6 +1,6 @@
1
- <% if can? :read, Webhooks::Outgoing::Delivery.new(team: current_team) %>
1
+ <% if can? :read, Webhooks::Outgoing::Delivery.new(BulletTrain::OutgoingWebhooks.parent_association => send(BulletTrain::OutgoingWebhooks.current_parent_method)) %>
2
2
  <%= render 'account/shared/menu/item', {
3
- url: main_app.polymorphic_path([:account, current_team, :webhooks_outgoing_deliveries]),
3
+ url: main_app.polymorphic_path([:account, send(BulletTrain::OutgoingWebhooks.current_parent_method), :webhooks_outgoing_deliveries]),
4
4
  label: t('webhooks/outgoing/deliveries.navigation.label'),
5
5
  } do |p| %>
6
6
  <% p.content_for :icon do %>
@@ -1,6 +1,6 @@
1
- <% if can? :read, Webhooks::Outgoing::DeliveryAttempt.new(team: current_team) %>
1
+ <% if can? :read, Webhooks::Outgoing::DeliveryAttempt.new(BulletTrain::OutgoingWebhooks.parent_association => send(BulletTrain::OutgoingWebhooks.current_parent_method)) %>
2
2
  <%= render 'account/shared/menu/item', {
3
- url: main_app.polymorphic_path([:account, current_team, :webhooks_outgoing_delivery_attempts]),
3
+ url: main_app.polymorphic_path([:account, send(BulletTrain::OutgoingWebhooks.current_parent_method), :webhooks_outgoing_delivery_attempts]),
4
4
  label: t('webhooks/outgoing/delivery_attempts.navigation.label'),
5
5
  } do |p| %>
6
6
  <% p.content_for :icon do %>
@@ -1,5 +1,5 @@
1
1
  <% endpoint ||= @endpoint %>
2
- <% team ||= @team || endpoint&.team %>
2
+ <% team ||= @parent || endpoint&.send(BulletTrain::OutgoingWebhooks.parent_association) %>
3
3
  <%= render 'account/teams/breadcrumbs', team: team %>
4
4
  <%= render 'account/shared/breadcrumb', label: t('.label'), url: [:account, team, :webhooks_outgoing_endpoints] %>
5
5
  <% if endpoint&.persisted? %>
@@ -1,4 +1,4 @@
1
- <%= form_with model: endpoint, url: (endpoint.persisted? ? [:account, endpoint] : [:account, @team, :webhooks_outgoing_endpoints]), local: true, class: 'form' do |form| %>
1
+ <%= form_with model: endpoint, url: (endpoint.persisted? ? [:account, endpoint] : [:account, @parent, :webhooks_outgoing_endpoints]), local: true, class: 'form' do |form| %>
2
2
  <%= render 'account/shared/forms/errors', form: form %>
3
3
 
4
4
  <% with_field_settings form: form do %>
@@ -14,7 +14,7 @@
14
14
  <% if form.object.persisted? %>
15
15
  <%= link_to t('global.buttons.cancel'), [:account, endpoint], class: "button-secondary" %>
16
16
  <% else %>
17
- <%= link_to t('global.buttons.cancel'), [:account, @team, :webhooks_outgoing_endpoints], class: "button-secondary" %>
17
+ <%= link_to t('global.buttons.cancel'), [:account, @parent, :webhooks_outgoing_endpoints], class: "button-secondary" %>
18
18
  <% end %>
19
19
  </div>
20
20
 
@@ -1,4 +1,4 @@
1
- <% team = @team || @team %>
1
+ <% team = @parent %>
2
2
  <% context ||= team %>
3
3
  <% collection ||= :webhooks_outgoing_endpoints %>
4
4
  <% hide_actions ||= false %>
@@ -49,8 +49,8 @@
49
49
  <% p.content_for :actions do %>
50
50
  <% unless hide_actions %>
51
51
  <% if context == team %>
52
- <% if can? :create, Webhooks::Outgoing::Endpoint.new(team: team) %>
53
- <%= link_to t('.buttons.new'), [:new, :account, team, :webhooks_outgoing_endpoint], class: "#{first_button_primary(:webhooks_outgoing_endpoint)} new" %>
52
+ <% if can? :create, Webhooks::Outgoing::Endpoint.new(BulletTrain::OutgoingWebhooks.parent_association => @parent) %>
53
+ <%= link_to t('.buttons.new'), [:new, :account, @parent, :webhooks_outgoing_endpoint], class: "#{first_button_primary(:webhooks_outgoing_endpoint)} new" %>
54
54
  <% end %>
55
55
  <% end %>
56
56
 
@@ -1,6 +1,6 @@
1
- <% if can? :read, Webhooks::Outgoing::Endpoint.new(team: current_team) %>
1
+ <% if can? :read, Webhooks::Outgoing::Endpoint.new(BulletTrain::OutgoingWebhooks.parent_association => send(BulletTrain::OutgoingWebhooks.current_parent_method)) %>
2
2
  <%= render 'account/shared/menu/item', {
3
- url: main_app.polymorphic_path([:account, current_team, :webhooks_outgoing_endpoints]),
3
+ url: main_app.polymorphic_path([:account, send(BulletTrain::OutgoingWebhooks.current_parent_method), :webhooks_outgoing_endpoints]),
4
4
  label: t('webhooks/outgoing/endpoints.navigation.label'),
5
5
  } do |p| %>
6
6
  <% p.content_for :icon do %>
@@ -32,7 +32,7 @@
32
32
  <% p.content_for :actions do %>
33
33
  <%= link_to t('.buttons.edit'), [:edit, :account, @endpoint], class: first_button_primary if can? :edit, @endpoint %>
34
34
  <%= button_to t('.buttons.destroy'), [:account, @endpoint], method: :delete, class: first_button_primary, data: { confirm: t('.buttons.confirmations.destroy', model_locales(@endpoint)) } if can? :destroy, @endpoint %>
35
- <%= link_to t('global.buttons.back'), [:account, @team, :webhooks_outgoing_endpoints], class: first_button_primary %>
35
+ <%= link_to t('global.buttons.back'), [:account, @parent, :webhooks_outgoing_endpoints], class: first_button_primary %>
36
36
  <% end %>
37
37
  <% end %>
38
38
 
data/config/routes.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  Rails.application.routes.draw do
2
2
  namespace :account do
3
3
  shallow do
4
- resources :teams do
4
+ resources BulletTrain::OutgoingWebhooks.parent_resource do
5
5
  namespace :webhooks do
6
6
  namespace :outgoing do
7
7
  resources :events
@@ -0,0 +1,10 @@
1
+ class CreateWebhooksOutgoingEndpoints < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_endpoints do |t|
4
+ t.references :team, foreign_key: true
5
+ t.text :url
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ class CreateWebhooksOutgoingEndpointEventTypes < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_endpoint_event_types do |t|
4
+ t.integer :endpoint_id
5
+ t.integer :event_type_id
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class CreateWebhooksOutgoingEventTypes < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_event_types do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateWebhooksOutgoingEvents < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_events do |t|
4
+ t.integer :event_type_id
5
+ t.integer :subject_id
6
+ t.string :subject_type
7
+ t.jsonb :body
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateWebhooksOutgoingDeliveries < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_deliveries do |t|
4
+ t.integer :endpoint_id
5
+ t.integer :event_id
6
+ t.text :endpoint_url
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class AddTeamToWebhooksOutgoingEvents < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_reference :webhooks_outgoing_events, :team, foreign_key: true
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class CreateWebhooksOutgoingDeliveryAttempts < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :webhooks_outgoing_delivery_attempts do |t|
4
+ t.integer :delivery_id
5
+ t.integer :response_code
6
+ t.text :response_body
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ class AddErrorMessageToWebhooksOutgoingDeliveryAttempt < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_delivery_attempts, :response_message, :text
4
+ add_column :webhooks_outgoing_delivery_attempts, :error_message, :text
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddNameToWebhooksOutgoingEndpoints < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_endpoints, :name, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddDeliveredAtToWebhooksOutgoingDeliveries < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_deliveries, :delivered_at, :datetime
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddUuidToWebhooksOutgoingEvents < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_events, :uuid, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddPayloadToWebhooksOutgoingEvents < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_events, :payload, :jsonb
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddAttemptNumberToWebhooksOutgoingDeliveryAttempts < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :webhooks_outgoing_delivery_attempts, :attempt_number, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class ChangeBodyToDataOnWebhooksOutgoingEvents < ActiveRecord::Migration[6.1]
2
+ def change
3
+ rename_column :webhooks_outgoing_events, :body, :data
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddEventTypeIdsToWebhooksOutgoingEndpoints < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :webhooks_outgoing_endpoints, :event_type_ids, :jsonb, default: []
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class MigrateEventTypeIdsOnWebhooksOutgoingEndpoints < ActiveRecord::Migration[6.1]
2
+ def change
3
+ Webhooks::Outgoing::Endpoint.find_each do |endpoint|
4
+ event_type_ids = ActiveRecord::Base.connection.execute("SELECT * FROM webhooks_outgoing_endpoint_event_types JOIN webhooks_outgoing_event_types ON webhooks_outgoing_endpoint_event_types.event_type_id = webhooks_outgoing_event_types.id WHERE endpoint_id = #{endpoint.id}").to_a.map { |result| result.dig("name") }
5
+ endpoint.update(event_type_ids: event_type_ids)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class RemoveEventTypeFromWebhooksOutgoingEvents < ActiveRecord::Migration[6.1]
2
+ def change
3
+ remove_reference :webhooks_outgoing_events, :event_type, null: false, foreign_key: false
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddNewEventTypeIdToWebhooksOutgoingEvents < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_column :webhooks_outgoing_events, :event_type_id, :string
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ class MigrateEventTypesOnWebhooksOutgoingEvents < ActiveRecord::Migration[6.1]
2
+ def up
3
+ Webhooks::Outgoing::Event.find_each do |event|
4
+ event.update_column(:event_type_id, event.payload.dig("event_type"))
5
+ end
6
+ end
7
+
8
+ def down
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ class DropWebhooksOutgoingEndpointEventTypes < ActiveRecord::Migration[6.1]
2
+ def up
3
+ drop_table :webhooks_outgoing_endpoint_event_types
4
+ end
5
+
6
+ def down
7
+ raise ActiveRecord::IrreversibleMigration
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class DropWebhooksOutgoingEventTypes < ActiveRecord::Migration[6.1]
2
+ def up
3
+ drop_table :webhooks_outgoing_event_types
4
+ end
5
+
6
+ def down
7
+ raise ActiveRecord::IrreversibleMigration
8
+ end
9
+ end
@@ -1,6 +1,38 @@
1
1
  module BulletTrain
2
2
  module OutgoingWebhooks
3
3
  class Engine < ::Rails::Engine
4
+ config.before_configuration do
5
+ default_blocked_cidrs = %w[
6
+ 10.0.0.0/8
7
+ 172.16.0.0/12
8
+ 192.168.0.0/16
9
+ 100.64.0.0/10
10
+ 127.0.0.0/8
11
+ 169.254.169.254/32
12
+ fc00::/7
13
+ ::1
14
+ ]
15
+
16
+ config.outgoing_webhooks = {
17
+ blocked_cidrs: default_blocked_cidrs,
18
+ allowed_cidrs: [],
19
+ blocked_hostnames: %w[localhost],
20
+ allowed_hostnames: [],
21
+ public_resolvers: %w[8.8.8.8 1.1.1.1],
22
+ allowed_schemes: %w[http https],
23
+ custom_block_callback: nil,
24
+ custom_allow_callback: nil,
25
+ audit_callback: ->(obj, uri) { Rails.logger.error("BlockedURI obj=#{obj.persisted? ? obj.to_global_id : "New #{obj.class}"} uri=#{uri}") }
26
+ }
27
+ end
28
+
29
+ initializer "bullet_train.outgoing_webhooks.register_api_endpoints" do |app|
30
+ if Object.const_defined?("BulletTrain::Api")
31
+ BulletTrain::Api.endpoints << "Api::V1::Webhooks::Outgoing::EndpointsEndpoint"
32
+ BulletTrain::Api.endpoints << "Api::V1::Webhooks::Outgoing::DeliveriesEndpoint"
33
+ BulletTrain::Api.endpoints << "Api::V1::Webhooks::Outgoing::DeliveryAttemptsEndpoint"
34
+ end
35
+ end
4
36
  end
5
37
  end
6
38
  end
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module OutgoingWebhooks
3
- VERSION = "1.0.2"
3
+ VERSION = "1.0.5"
4
4
  end
5
5
  end