trello_webhook 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4b516b3bbf281076131e7425b83785c805ee142c
4
+ data.tar.gz: ffd3fe3ca304c6bb3838c953e8f54a7648e3d939
5
+ SHA512:
6
+ metadata.gz: b67b80ba9683a4112430f15214baa95c0e803126e713add3d1c2f65110d103b9fcc676610ad42c06e358e33c642a059053b07be8a754e6bef4a2e66ffa86f19f
7
+ data.tar.gz: 4391bf738eefe3787fa7bfd7c2dd4f737b865c3b6b8f84893db1a41fffc866df1af0797395c81ff8e4ae540a3a7af9f3e59d811c30e047ae5fc9a3f33212bf0c
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ *.gem
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.0
4
+ - 2.1.0
5
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in trello_webhook.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ trello_webhook (0.1.0)
5
+ activesupport (~> 4)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (4.2.0)
11
+ i18n (~> 0.7)
12
+ json (~> 1.7, >= 1.7.7)
13
+ minitest (~> 5.1)
14
+ thread_safe (~> 0.3, >= 0.3.4)
15
+ tzinfo (~> 1.1)
16
+ diff-lcs (1.2.5)
17
+ i18n (0.7.0)
18
+ json (1.8.2)
19
+ minitest (5.5.1)
20
+ rake (10.3.1)
21
+ rspec (2.14.1)
22
+ rspec-core (~> 2.14.0)
23
+ rspec-expectations (~> 2.14.0)
24
+ rspec-mocks (~> 2.14.0)
25
+ rspec-core (2.14.8)
26
+ rspec-expectations (2.14.5)
27
+ diff-lcs (>= 1.1.3, < 2.0)
28
+ rspec-mocks (2.14.6)
29
+ thread_safe (0.3.4)
30
+ tzinfo (1.2.2)
31
+ thread_safe (~> 0.1)
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ bundler (~> 1.5)
38
+ rake (~> 10.1)
39
+ rspec (~> 2.14)
40
+ trello_webhook!
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Sebastien Saunier
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ [![Build Status](https://travis-ci.org/ssaunier/trello_webhook.svg?branch=master)](https://travis-ci.org/ssaunier/trello_webhook)
2
+ [![Gem Version](https://badge.fury.io/rb/trello_webhook.svg)](http://badge.fury.io/rb/trello_webhook)
3
+
4
+
5
+ # TrelloWebhook
6
+
7
+ This gem will help you to quickly setup a route in your Rails application which listens
8
+ to a [Trello webhook](https://trello.com/docs/api/webhook/index.html)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'trello_webhook'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ ```bash
21
+ $ bundle install
22
+ ```
23
+
24
+ ## Configuration
25
+
26
+ First, configure a route to receive the trello webhook POST requests.
27
+
28
+ ```ruby
29
+ # config/routes.rb
30
+ resource :trello_webhooks, only: %i(show create), defaults: { formats: :json }
31
+ ```
32
+
33
+ Then create a new controller:
34
+
35
+ ```ruby
36
+ # app/controllers/trello_webhooks_controller.rb
37
+ class TrelloWebhooksController < ActionController::Base
38
+ include TrelloWebhook::Processor
39
+
40
+ def update_card(payload)
41
+ # TODO: handle updateCard webhook payload
42
+ end
43
+
44
+ def webhook_secret
45
+ ENV['TRELLO_DEVELOPER_SECRET'] # From https://trello.com/app-key
46
+ end
47
+ end
48
+ ```
49
+
50
+ Add as many instance methods as events you want to handle in your controller.
51
+
52
+ ## Adding the webhook to a given board
53
+
54
+ You need the `ruby-trello` gem.
55
+
56
+ ```ruby
57
+ webhook = Trello::Webhook.new
58
+ webhook.description = "The webhook description"
59
+ webhook.id_model = "The board model id" # Run `Trello::Board.all` to find it.
60
+ webhook.callback_url = "#{ENV['BASE_URL']}/trello_webhooks" # BASE_URL is your website's url. Use ngrok in dev.
61
+ webhook.save
62
+ ```
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec'
5
+ require 'rspec/core/rake_task'
6
+
7
+ desc "Run all RSpec test examples"
8
+ RSpec::Core::RakeTask.new do |spec|
9
+ spec.rspec_opts = ["-c", "-f progress"]
10
+ spec.pattern = 'spec/**/*_spec.rb'
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,66 @@
1
+ module TrelloWebhook::Processor
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ before_filter :authenticate_trello_request!, :only => :create
6
+ end
7
+
8
+ class SignatureError < StandardError; end
9
+ class UnspecifiedWebhookSecretError < StandardError; end
10
+ class CallbackNotImplementedError < StandardError; end
11
+
12
+ def create
13
+ if self.respond_to? event
14
+ self.send event, json_body
15
+ head(:ok)
16
+ else
17
+ fail CallbackNotImplementedError, "#{self.class.name}##{event} not implemented"
18
+ end
19
+ end
20
+
21
+ def show
22
+ if request.head?
23
+ puts "[TrelloWebhook::Processor] Hook ping received"
24
+ p request_body
25
+ head :ok
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ HMAC_DIGEST = OpenSSL::Digest.new('sha1')
32
+
33
+ def authenticate_trello_request!
34
+ raise UnspecifiedWebhookSecretError.new unless respond_to?(:webhook_secret)
35
+
36
+ normalized_payload = "#{request_body}#{request_url}".unpack('U*').pack('c*')
37
+ expected_signature = Base64.strict_encode64(OpenSSL::HMAC.digest(HMAC_DIGEST, webhook_secret, normalized_payload))
38
+
39
+ if signature_header != expected_signature
40
+ raise SignatureError.new "Actual: #{signature_header}, Expected: #{expected_signature}"
41
+ end
42
+ end
43
+
44
+ def request_body
45
+ @request_body ||= (
46
+ request.body.rewind
47
+ request.body.read
48
+ )
49
+ end
50
+
51
+ def request_url
52
+ request.original_url
53
+ end
54
+
55
+ def json_body
56
+ @json_body ||= ActiveSupport::HashWithIndifferentAccess.new(JSON.load(request_body))
57
+ end
58
+
59
+ def signature_header
60
+ @signature_header ||= request.headers['X-Trello-Webhook']
61
+ end
62
+
63
+ def event
64
+ @event ||= json_body["action"]["type"].underscore
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module TrelloWebhook
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'active_support/concern'
5
+ require 'active_support/inflector'
6
+ require 'active_support/core_ext/hash/indifferent_access'
7
+
8
+ require 'trello_webhook/version'
9
+ require 'trello_webhook/processor'
@@ -0,0 +1,10 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+
3
+ require "trello_webhook"
4
+
5
+ # Load support files
6
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
7
+
8
+ RSpec.configure do |config|
9
+ config.order = "random"
10
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ module TrelloWebhook
4
+ describe Processor do
5
+
6
+ class Request
7
+ attr_accessor :headers, :body
8
+
9
+ def initialize
10
+ @headers = {}
11
+ @body = StringIO.new
12
+ end
13
+
14
+ def original_url
15
+ "http://foo.com"
16
+ end
17
+ end
18
+
19
+ class ControllerWithoutSecret
20
+ ### Helpers to mock ActionController::Base behavior
21
+ attr_accessor :request, :updated
22
+
23
+ def self.skip_before_filter(*args); end
24
+ def self.before_filter(*args); end
25
+ def head(*args); end
26
+ ###
27
+
28
+ include TrelloWebhook::Processor
29
+
30
+ def update_card(payload)
31
+ @updated = payload[:foo]
32
+ end
33
+ end
34
+
35
+ class Controller < ControllerWithoutSecret
36
+ def webhook_secret
37
+ "secret"
38
+ end
39
+ end
40
+
41
+ let(:controller) do
42
+ controller = Controller.new
43
+ controller.request = Request.new
44
+ controller
45
+ end
46
+
47
+ let(:controller_without_secret) do
48
+ ControllerWithoutSecret.new
49
+ end
50
+
51
+ describe "#create" do
52
+ it "raises an error when secret is not defined" do
53
+ expect { controller_without_secret.send :authenticate_trello_request! }.to raise_error
54
+ end
55
+
56
+ it "calls the #update_card method in controller" do
57
+ controller.request.body = StringIO.new({ :foo => "bar", :action => { type: 'updateCard' } }.to_json.to_s)
58
+ controller.request.headers['X-Trello-Webhook'] = "3YUv3UBpzV8IbZrOnIpRC+Cf+Nk="
59
+ controller.send :authenticate_trello_request! # Manually as we don't have the before_filter logic in our Mock object
60
+ controller.create
61
+ expect(controller.updated).to eq "bar"
62
+ end
63
+
64
+ it "raises an error when signature does not match" do
65
+ controller.request.body = StringIO.new({ :foo => "bar" }.to_json.to_s)
66
+ controller.request.headers['X-Trello-Webhook'] = "thatsnotrightgeorge"
67
+ expect { controller_without_secret.send :authenticate_trello_request! }.to raise_error
68
+ end
69
+
70
+ it "raises an error when the trello event method is not implemented" do
71
+ expect { controller_without_secret.create }.to raise_error
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'trello_webhook/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "trello_webhook"
8
+ spec.version = TrelloWebhook::VERSION
9
+ spec.authors = ["Sebastien Saunier"]
10
+ spec.email = ["seb@saunier.me"]
11
+ spec.summary = %q{Process Trello Webhooks in your Rails app (Controller mixin)}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/ssaunier/trello_webhook"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport", "~> 4"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.5"
24
+ spec.add_development_dependency "rake", "~> 10.1"
25
+ spec.add_development_dependency "rspec", "~> 2.14"
26
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trello_webhook
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sebastien Saunier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ description: Process Trello Webhooks in your Rails app (Controller mixin)
70
+ email:
71
+ - seb@saunier.me
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - lib/trello_webhook.rb
84
+ - lib/trello_webhook/processor.rb
85
+ - lib/trello_webhook/version.rb
86
+ - spec/spec_helper.rb
87
+ - spec/trello_webhook/processor_spec.rb
88
+ - trello_webhook.gemspec
89
+ homepage: https://github.com/ssaunier/trello_webhook
90
+ licenses:
91
+ - MIT
92
+ metadata: {}
93
+ post_install_message:
94
+ rdoc_options: []
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.4.5
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Process Trello Webhooks in your Rails app (Controller mixin)
113
+ test_files:
114
+ - spec/spec_helper.rb
115
+ - spec/trello_webhook/processor_spec.rb