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.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/app/assets/config/{bullet_train_outgoing_webhooks_web_manifest.js → bullet_train_outgoing_webhooks_manifest.js} +0 -0
- data/app/controllers/account/webhooks/outgoing/endpoints_controller.rb +4 -3
- data/app/controllers/api/v1/webhooks/outgoing/deliveries_endpoint.rb +63 -0
- data/app/controllers/api/v1/webhooks/outgoing/delivery_attempts_endpoint.rb +65 -0
- data/app/controllers/api/v1/webhooks/outgoing/endpoints_endpoint.rb +119 -0
- data/app/jobs/webhooks/outgoing/delivery_job.rb +7 -0
- data/app/jobs/webhooks/outgoing/generate_job.rb +7 -0
- data/app/models/concerns/webhooks/outgoing/delivery_attempt_support.rb +64 -0
- data/app/models/concerns/webhooks/outgoing/delivery_support.rb +66 -0
- data/app/models/concerns/webhooks/outgoing/endpoint_support.rb +37 -0
- data/app/models/concerns/webhooks/outgoing/event_support.rb +45 -0
- data/app/models/concerns/webhooks/outgoing/issuing_model.rb +67 -0
- data/app/models/concerns/webhooks/outgoing/team_support.rb +31 -0
- data/app/models/concerns/webhooks/outgoing/uri_filtering.rb +149 -0
- data/app/models/webhooks/outgoing/delivery.rb +20 -0
- data/app/models/webhooks/outgoing/delivery_attempt.rb +20 -0
- data/app/models/webhooks/outgoing/endpoint.rb +20 -0
- data/app/models/webhooks/outgoing/event.rb +3 -0
- data/app/models/webhooks/outgoing/event_type.rb +13 -0
- data/app/models/webhooks/outgoing.rb +5 -0
- data/app/models/webhooks.rb +5 -0
- data/app/serializers/api/v1/webhooks/outgoing/delivery_attempt_serializer.rb +16 -0
- data/app/serializers/api/v1/webhooks/outgoing/delivery_serializer.rb +14 -0
- data/app/serializers/api/v1/webhooks/outgoing/endpoint_serializer.rb +14 -0
- data/app/views/account/webhooks/outgoing/deliveries/_menu_item.html.erb +2 -2
- data/app/views/account/webhooks/outgoing/delivery_attempts/_menu_item.html.erb +2 -2
- data/app/views/account/webhooks/outgoing/endpoints/_breadcrumbs.html.erb +1 -1
- data/app/views/account/webhooks/outgoing/endpoints/_form.html.erb +2 -2
- data/app/views/account/webhooks/outgoing/endpoints/_index.html.erb +3 -3
- data/app/views/account/webhooks/outgoing/endpoints/_menu_item.html.erb +2 -2
- data/app/views/account/webhooks/outgoing/endpoints/show.html.erb +1 -1
- data/config/routes.rb +1 -1
- data/db/migrate/20180420013127_create_webhooks_outgoing_endpoints.rb +10 -0
- data/db/migrate/20180420013505_create_webhooks_outgoing_endpoint_event_types.rb +10 -0
- data/db/migrate/20180420013852_create_webhooks_outgoing_event_types.rb +9 -0
- data/db/migrate/20180420014623_create_webhooks_outgoing_events.rb +12 -0
- data/db/migrate/20180420021016_create_webhooks_outgoing_deliveries.rb +11 -0
- data/db/migrate/20180420022027_add_team_to_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20180420165345_create_webhooks_outgoing_delivery_attempts.rb +11 -0
- data/db/migrate/20180420172112_add_error_message_to_webhooks_outgoing_delivery_attempt.rb +6 -0
- data/db/migrate/20181012234232_add_name_to_webhooks_outgoing_endpoints.rb +5 -0
- data/db/migrate/20181013030208_add_delivered_at_to_webhooks_outgoing_deliveries.rb +5 -0
- data/db/migrate/20181013165056_add_uuid_to_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20181013174539_add_payload_to_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20181013192951_add_attempt_number_to_webhooks_outgoing_delivery_attempts.rb +5 -0
- data/db/migrate/20210805060451_change_body_to_data_on_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20211126230846_add_event_type_ids_to_webhooks_outgoing_endpoints.rb +5 -0
- data/db/migrate/20211126230847_migrate_event_type_ids_on_webhooks_outgoing_endpoints.rb +8 -0
- data/db/migrate/20211127013539_remove_event_type_from_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20211127013800_add_new_event_type_id_to_webhooks_outgoing_events.rb +5 -0
- data/db/migrate/20211127014001_migrate_event_types_on_webhooks_outgoing_events.rb +10 -0
- data/db/migrate/20211127015712_drop_webhooks_outgoing_endpoint_event_types.rb +9 -0
- data/db/migrate/20211127015713_drop_webhooks_outgoing_event_types.rb +9 -0
- data/lib/bullet_train/outgoing_webhooks/engine.rb +32 -0
- data/lib/bullet_train/outgoing_webhooks/version.rb +1 -1
- data/lib/bullet_train/outgoing_webhooks.rb +28 -3
- 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,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,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(
|
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,
|
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(
|
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,
|
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 ||= @
|
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, @
|
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, @
|
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 = @
|
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(
|
53
|
-
<%= link_to t('.buttons.new'), [:new, :account,
|
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(
|
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,
|
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, @
|
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
@@ -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,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
|
@@ -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
|