webhookr 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +1937 -0
- data/.travis.yml +8 -8
- data/Gemfile +12 -15
- data/Guardfile +12 -15
- data/MIT-LICENSE +1 -1
- data/README.md +8 -7
- data/Rakefile +3 -3
- data/app/controllers/webhookr/events_controller.rb +23 -16
- data/config/routes.rb +9 -8
- data/lib/generators/webhookr/add_route_generator.rb +4 -4
- data/lib/generators/webhookr/init_generator.rb +14 -12
- data/lib/tasks/webhookr_tasks.rake +7 -7
- data/lib/webhookr.rb +13 -6
- data/lib/webhookr/adapter_response.rb +3 -1
- data/lib/webhookr/engine.rb +5 -4
- data/lib/webhookr/invalid_payload_error.rb +8 -2
- data/lib/webhookr/invalid_security_token_error.rb +3 -1
- data/lib/webhookr/invalid_service_name_error.rb +9 -0
- data/lib/webhookr/missing_callback_class_error.rb +9 -0
- data/lib/webhookr/ostruct_utils.rb +19 -19
- data/lib/webhookr/service.rb +28 -24
- data/lib/webhookr/services.rb +1 -1
- data/lib/webhookr/services/adapter.rb +1 -1
- data/lib/webhookr/services/adapter/base.rb +2 -2
- data/lib/webhookr/version.rb +3 -1
- data/test/dummy/Rakefile +0 -1
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/config.ru +1 -1
- data/test/dummy/config/application.rb +8 -8
- data/test/dummy/config/boot.rb +4 -1
- data/test/dummy/config/environment.rb +2 -0
- data/test/dummy/config/environments/development.rb +2 -1
- data/test/dummy/config/environments/production.rb +2 -1
- data/test/dummy/config/environments/test.rb +5 -4
- data/test/dummy/config/initializers/backtrace_silencers.rb +2 -0
- data/test/dummy/config/initializers/inflections.rb +2 -0
- data/test/dummy/config/initializers/mime_types.rb +2 -0
- data/test/dummy/config/initializers/secret_token.rb +3 -1
- data/test/dummy/config/initializers/session_store.rb +3 -1
- data/test/dummy/config/initializers/webhookr.rb +3 -1
- data/test/dummy/config/initializers/wrap_parameters.rb +3 -2
- data/test/dummy/config/routes.rb +3 -1
- data/test/dummy/script/rails +2 -2
- data/test/functional/webhookr/events_controller_test.rb +38 -42
- data/test/functional/webhookr/events_routes_test.rb +22 -15
- data/test/functional/webhookr/service_test.rb +53 -48
- data/test/integration/webhookr/add_route_generator_test.rb +5 -4
- data/test/integration/webhookr/init_generator_test.rb +7 -6
- data/test/stubs/service_under_test_stubs.rb +26 -33
- data/test/test_helper.rb +10 -9
- data/test/unit/webhookr/adapter_response_test.rb +7 -6
- data/test/unit/webhookr/ostruct_utils_test.rb +14 -14
- data/test/unit/webhookr/{Services/ServiceUnderTest → services/service_under_test}/adapter_test.rb +14 -14
- data/test/webhookr_test.rb +5 -3
- data/webhookr.gemspec +3 -4
- metadata +24 -27
@@ -1,28 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Webhookr
|
2
4
|
# Adapted from http://www.rebeccamiller-webster.com/2012/06/recursively-convert-a-ruby-hash-to-openstruct/
|
3
5
|
module OstructUtils
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
return array_to_ostruct(obj)
|
6
|
+
def self.to_ostruct(obj)
|
7
|
+
case obj
|
8
|
+
when Hash
|
9
|
+
hash_to_ostruct(obj)
|
10
|
+
when Array
|
11
|
+
array_to_ostruct(obj)
|
11
12
|
else
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.hash_to_ostruct(hash)
|
17
|
-
hash.each do |key, val|
|
18
|
-
hash[key] = to_ostruct(val)
|
19
|
-
end
|
20
|
-
OpenStruct.new(hash)
|
13
|
+
obj
|
21
14
|
end
|
15
|
+
end
|
22
16
|
|
23
|
-
|
24
|
-
|
17
|
+
def self.hash_to_ostruct(hash)
|
18
|
+
hash.each do |key, val|
|
19
|
+
hash[key] = to_ostruct(val)
|
25
20
|
end
|
21
|
+
OpenStruct.new(hash)
|
22
|
+
end
|
26
23
|
|
24
|
+
def self.array_to_ostruct(array)
|
25
|
+
array.map { |r| to_ostruct(r) }
|
26
|
+
end
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end
|
data/lib/webhookr/service.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Webhookr
|
2
4
|
class Service
|
3
5
|
attr_reader :service_name
|
4
6
|
|
5
7
|
def initialize(service_name, options = {})
|
6
|
-
@service_name = (service_name ||
|
8
|
+
@service_name = (service_name || '').downcase
|
7
9
|
@raw_payload = options[:payload]
|
8
10
|
available?
|
9
11
|
validate_security_token(options[:security_token]) if configured_security_token
|
@@ -17,35 +19,37 @@ module Webhookr
|
|
17
19
|
|
18
20
|
private
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
def callback(object, payload)
|
23
|
+
method = method_for(payload)
|
24
|
+
object.send(method, payload) if object.respond_to?(method)
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
def method_for(payload)
|
28
|
+
"on_#{payload.event_type}"
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
@call_back_class || callback.new
|
33
|
-
end
|
31
|
+
def callback_class
|
32
|
+
callback = Webhookr.config[service_name].try(:callback)
|
33
|
+
raise Webhookr::MissingCallbackClassError, service_name if callback.nil?
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
end
|
35
|
+
@call_back_class || callback.new
|
36
|
+
end
|
38
37
|
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
def configured_security_token
|
39
|
+
Webhookr.config[service_name].try(:security_token)
|
40
|
+
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
42
|
+
def validate_security_token(token)
|
43
|
+
raise Webhookr::InvalidSecurityTokenError if token.nil? || !SecureCompare.compare(token, configured_security_token)
|
44
|
+
end
|
47
45
|
|
48
|
-
|
46
|
+
def service_adapter
|
47
|
+
raise Webhookr::InvalidServiceNameError, service_name unless Webhookr.adapters[service_name]
|
48
|
+
@service_adapter ||= Webhookr.adapters[service_name]
|
49
|
+
end
|
49
50
|
|
51
|
+
def available?
|
52
|
+
!!service_adapter
|
53
|
+
end
|
50
54
|
end
|
51
55
|
end
|
data/lib/webhookr/services.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
module Webhookr::Services::Adapter::Base
|
3
4
|
extend ActiveSupport::Concern
|
4
5
|
|
5
6
|
included do
|
6
|
-
|
7
|
+
initialize! if respond_to?(:initialize!)
|
7
8
|
Webhookr.adapters[self::SERVICE_NAME] = self
|
8
9
|
end
|
9
10
|
|
@@ -17,4 +18,3 @@ module Webhookr::Services::Adapter::Base
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
20
|
-
|
data/lib/webhookr/version.rb
CHANGED
data/test/dummy/Rakefile
CHANGED
data/test/dummy/config.ru
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require File.expand_path('../boot', __FILE__)
|
2
4
|
|
3
5
|
# Pick the frameworks you want:
|
4
6
|
# require "active_record/railtie"
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
7
|
+
require 'action_controller/railtie'
|
8
|
+
require 'sprockets/railtie'
|
9
|
+
require 'rails/test_unit/railtie'
|
8
10
|
|
9
11
|
Bundler.require
|
10
|
-
require
|
12
|
+
require 'webhookr'
|
11
13
|
|
12
14
|
module Dummy
|
13
15
|
class Application < Rails::Application
|
@@ -16,7 +18,7 @@ module Dummy
|
|
16
18
|
# -- all .rb files in that directory are automatically loaded.
|
17
19
|
|
18
20
|
# Custom directories with classes and modules you want to be autoloadable.
|
19
|
-
config.autoload_paths += %W
|
21
|
+
config.autoload_paths += %W{#{config.root}/../../lib}
|
20
22
|
|
21
23
|
# Only load the plugins named here, in the order given (default is alphabetical).
|
22
24
|
# :all can be used as a placeholder for all plugins not explicitly named.
|
@@ -34,7 +36,7 @@ module Dummy
|
|
34
36
|
# config.i18n.default_locale = :de
|
35
37
|
|
36
38
|
# Configure the default encoding used in templates for Ruby 1.9.
|
37
|
-
config.encoding =
|
39
|
+
config.encoding = 'utf-8'
|
38
40
|
|
39
41
|
# Configure sensitive parameters which will be filtered from the log file.
|
40
42
|
config.filter_parameters += [:password]
|
@@ -58,7 +60,5 @@ module Dummy
|
|
58
60
|
|
59
61
|
# Version of your assets, change this if you want to expire all your assets
|
60
62
|
config.assets.version = '1.0'
|
61
|
-
|
62
63
|
end
|
63
64
|
end
|
64
|
-
|
data/test/dummy/config/boot.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rubygems'
|
4
|
+
|
2
5
|
gemfile = File.expand_path('../../../../Gemfile', __FILE__)
|
3
6
|
|
4
7
|
if File.exist?(gemfile)
|
@@ -7,4 +10,4 @@ if File.exist?(gemfile)
|
|
7
10
|
Bundler.setup
|
8
11
|
end
|
9
12
|
|
10
|
-
|
13
|
+
$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Dummy::Application.configure do
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb
|
3
5
|
|
@@ -19,7 +21,6 @@ Dummy::Application.configure do
|
|
19
21
|
# Only use best-standards-support built into browsers
|
20
22
|
config.action_dispatch.best_standards_support = :builtin
|
21
23
|
|
22
|
-
|
23
24
|
# Do not compress assets
|
24
25
|
config.assets.compress = false
|
25
26
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Dummy::Application.configure do
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb
|
3
5
|
|
@@ -60,5 +62,4 @@ Dummy::Application.configure do
|
|
60
62
|
|
61
63
|
# Send deprecation notices to registered listeners
|
62
64
|
config.active_support.deprecation = :notify
|
63
|
-
|
64
65
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Dummy::Application.configure do
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb
|
3
5
|
|
@@ -9,27 +11,26 @@ Dummy::Application.configure do
|
|
9
11
|
|
10
12
|
# Configure static asset server for tests with Cache-Control for performance
|
11
13
|
config.serve_static_assets = true
|
12
|
-
config.static_cache_control =
|
14
|
+
config.static_cache_control = 'public, max-age=3600'
|
13
15
|
|
14
16
|
# Rails 4.0
|
15
17
|
config.eager_load = false
|
16
18
|
|
17
19
|
# Show full error reports and disable caching
|
18
|
-
config.consider_all_requests_local
|
20
|
+
config.consider_all_requests_local = true
|
19
21
|
config.action_controller.perform_caching = false
|
20
22
|
|
21
23
|
# Raise exceptions instead of rendering exception templates
|
22
24
|
config.action_dispatch.show_exceptions = false
|
23
25
|
|
24
26
|
# Disable request forgery protection in test environment
|
25
|
-
config.action_controller.allow_forgery_protection
|
27
|
+
config.action_controller.allow_forgery_protection = false
|
26
28
|
|
27
29
|
# Tell Action Mailer not to deliver emails to the real world.
|
28
30
|
# The :test delivery method accumulates sent emails in the
|
29
31
|
# ActionMailer::Base.deliveries array.
|
30
32
|
# config.action_mailer.delivery_method = :test
|
31
33
|
|
32
|
-
|
33
34
|
# Print deprecation notices to the stderr
|
34
35
|
config.active_support.deprecation = :stderr
|
35
36
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Be sure to restart your server when you modify this file.
|
2
4
|
|
3
5
|
# Your secret key for verifying the integrity of signed cookies.
|
4
6
|
# If you change this key, all old signed cookies will become invalid!
|
5
7
|
# Make sure the secret is at least 30 characters and all random,
|
6
8
|
# no regular words or you'll be exposed to dictionary attacks.
|
7
|
-
Dummy::Application.config.secret_key_base = '37ef70b5f837f7a433cdd2a24cfac821c9e6624bccad494de69557a4d95e70d6400afb6c291fed109e417492c84c39d4325f35716fdc6c57cc376aacc72ad512'
|
9
|
+
Dummy::Application.config.secret_key_base = '37ef70b5f837f7a433cdd2a24cfac821c9e6624bccad494de69557a4d95e70d6400afb6c291fed109e417492c84c39d4325f35716fdc6c57cc376aacc72ad512'
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Be sure to restart your server when you modify this file.
|
2
4
|
|
3
|
-
Dummy::Application.config.session_store :cookie_store, :
|
5
|
+
Dummy::Application.config.session_store :cookie_store, key: '_dummy_session'
|
4
6
|
|
5
7
|
# Use the database for sessions instead of the cookie-based default,
|
6
8
|
# which shouldn't be used to store highly confidential information
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Be sure to restart your server when you modify this file.
|
2
4
|
#
|
3
5
|
# This file contains settings for ActionController::ParamsWrapper which
|
@@ -5,6 +7,5 @@
|
|
5
7
|
|
6
8
|
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
7
9
|
ActiveSupport.on_load(:action_controller) do
|
8
|
-
wrap_parameters :
|
10
|
+
wrap_parameters format: [:json]
|
9
11
|
end
|
10
|
-
|
data/test/dummy/config/routes.rb
CHANGED
data/test/dummy/script/rails
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
3
3
|
|
4
|
-
APP_PATH = File.expand_path('../../config/application',
|
5
|
-
require File.expand_path('../../config/boot',
|
4
|
+
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
5
|
+
require File.expand_path('../../config/boot', __FILE__)
|
6
6
|
require 'rails/commands'
|
@@ -1,76 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
|
-
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), %w{ .. .. })
|
3
4
|
require 'test_helper'
|
4
5
|
require 'stubs/service_under_test_stubs'
|
5
6
|
|
6
7
|
module Webhookr
|
7
8
|
class EventsControllerTest < ActionController::TestCase
|
8
|
-
|
9
9
|
include Webhookr::ServiceUnderTest
|
10
10
|
|
11
11
|
def setup
|
12
12
|
@routes = Webhookr::Engine.routes
|
13
13
|
PlainOldCallBackClass.reset!
|
14
14
|
Webhookr::ServiceUnderTest::Adapter.config.security_token = nil
|
15
|
-
@security_token =
|
15
|
+
@security_token = 'secure_blort'
|
16
16
|
end
|
17
17
|
|
18
|
-
test
|
19
|
-
assert_raise(ActionController::RoutingError)
|
20
|
-
get(:show, {:
|
21
|
-
|
18
|
+
test ':get with no service id should return a ActionController::RoutingError' do
|
19
|
+
assert_raise(ActionController::RoutingError) do
|
20
|
+
get(:show, params: { service_id: '' })
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
|
-
test
|
25
|
-
assert_raise(ActionController::RoutingError)
|
26
|
-
get(:show, {:
|
27
|
-
|
24
|
+
test ':get with an unknown service id should return a ActionController::RoutingError' do
|
25
|
+
assert_raise(ActionController::RoutingError) do
|
26
|
+
get(:show, params: { service_id: 'blort' })
|
27
|
+
end
|
28
28
|
end
|
29
29
|
|
30
|
-
test
|
31
|
-
get(:show, {:
|
30
|
+
test ':get with known service id should return success and an empty body' do
|
31
|
+
get(:show, params: { service_id: stub.service_name })
|
32
32
|
assert_response :success
|
33
|
-
assert(@response.body.blank?, "Expected an empty reponse, but got'#{@response.body}'")
|
33
|
+
assert(@response.body.blank?, "Expected an empty reponse, but got '#{@response.body}'")
|
34
34
|
end
|
35
35
|
|
36
|
-
test
|
36
|
+
test ':post with valid payload should return success' do
|
37
37
|
PlainOldCallBackClass.reset!
|
38
38
|
Webhookr::ServiceUnderTest::Adapter.config.callback = PlainOldCallBackClass
|
39
|
-
post(
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
post(
|
40
|
+
:create,
|
41
|
+
params: {
|
42
|
+
service_id: stub.service_name,
|
43
|
+
event: stub.event_type,
|
44
|
+
data: {
|
45
|
+
email: stub.email
|
46
|
+
}
|
47
|
+
}
|
48
|
+
)
|
45
49
|
assert_equal 1, PlainOldCallBackClass.call_count
|
46
50
|
end
|
47
51
|
|
48
|
-
test
|
52
|
+
test ':get with :security_token configured and not passed should return :InvalidAuthenticityToken' do
|
49
53
|
Webhookr::ServiceUnderTest::Adapter.config.security_token = @security_token
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
|
55
|
+
assert_raise(ActionController::InvalidAuthenticityToken) do
|
56
|
+
get(:show, params: { service_id: stub.service_name })
|
57
|
+
end
|
53
58
|
end
|
54
59
|
|
55
|
-
test
|
60
|
+
test ':get with :security_token configured and passed should return :success' do
|
56
61
|
Webhookr::ServiceUnderTest::Adapter.config.security_token = @security_token
|
57
|
-
get(
|
62
|
+
get(
|
63
|
+
:show,
|
64
|
+
params: {
|
65
|
+
service_id: stub.service_name,
|
66
|
+
security_token: @security_token
|
67
|
+
}
|
68
|
+
)
|
58
69
|
assert_response(:success)
|
59
70
|
end
|
60
|
-
|
61
|
-
test "basic auth will prevent unauthorized access" do
|
62
|
-
# pending "more time" do
|
63
|
-
# Webhookr.config.basic_auth.username = "admin"
|
64
|
-
# Webhookr.config.basic_auth.password = "password"
|
65
|
-
#
|
66
|
-
# post(:create, {
|
67
|
-
# :service_id => stub.service_name,
|
68
|
-
# :event => stub.event
|
69
|
-
# }
|
70
|
-
# )
|
71
|
-
# assert_response :unauthorized
|
72
|
-
# end
|
73
|
-
end
|
74
|
-
|
75
71
|
end
|
76
72
|
end
|