facebook-messenger 0.4.2 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8a7696b57e99d377b17191c4e5af80b046a510bc
4
- data.tar.gz: f5f3833b93525960127c6bb2531cbfa127ac125f
3
+ metadata.gz: 4cc6286ba13cf8c0c5239c5c50645cfce5af44c6
4
+ data.tar.gz: 1c8ab52a23996258d2f4db0254424727471c8c3e
5
5
  SHA512:
6
- metadata.gz: 7036944b12c06ba4de4263c1f17a46b2cc83f76b1b33933c1f02536144a459a36f2274f22912de0892e1e97a254a6a438cd45b73985eb63b7b706cdcd5081487
7
- data.tar.gz: a261a4406b6a5ef5685ec0dd9b634aaf28554b164ec03852f1d4a8fb15a24b081ad3c89ce3ae5420dc13bb6c8b4a6408cdd8fa31e8423a4dae0ed9d39c9f762b
6
+ metadata.gz: 0ecf386733c99eea428f1704d569703a8f2959412e4bde1139a0d64c5e4dc94d31d34ad9daeb95bd00dfd82de0af35128d7a9a011ffb9c41cc527dfa9c47b569
7
+ data.tar.gz: 09382794eb526905b5aa4d809156f05ac5dad9794ab920977dc1cb6ff98b47f954a4e0a350cdb86a1555731943ce195cad2fbd543dded414708a904aa1ee36fc
data/README.md CHANGED
@@ -8,6 +8,7 @@
8
8
  [![Dependency Status](https://img.shields.io/gemnasium/hyperoslo/facebook-messenger.svg?style=flat)](https://gemnasium.com/hyperoslo/facebook-messenger)
9
9
  [![Code Climate](https://img.shields.io/codeclimate/github/hyperoslo/facebook-messenger.svg?style=flat)](https://codeclimate.com/github/hyperoslo/facebook-messenger)
10
10
  [![Coverage Status](https://img.shields.io/coveralls/hyperoslo/facebook-messenger.svg?style=flat)](https://coveralls.io/r/hyperoslo/facebook-messenger)
11
+ [![Join the chat at https://gitter.im/hyperoslo/facebook-messenger](https://badges.gitter.im/hyperoslo/facebook-messenger.svg)](https://gitter.im/hyperoslo/facebook-messenger?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
11
12
 
12
13
  ## Installation
13
14
 
@@ -26,11 +27,12 @@ require 'facebook/messenger'
26
27
  include Facebook::Messenger
27
28
 
28
29
  Bot.on :message do |message|
29
- message.id # => 'mid.1457764197618:41d102a3e1ae206a38'
30
- message.sender # => { 'id' => '1008372609250235' }
31
- message.seq # => 73
32
- message.sent_at # => 2016-04-22 21:30:36 +0200
33
- message.text # => 'Hello, bot!'
30
+ message.id # => 'mid.1457764197618:41d102a3e1ae206a38'
31
+ message.sender # => { 'id' => '1008372609250235' }
32
+ message.seq # => 73
33
+ message.sent_at # => 2016-04-22 21:30:36 +0200
34
+ message.text # => 'Hello, bot!'
35
+ message.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]
34
36
 
35
37
  Bot.deliver(
36
38
  recipient: message.sender,
@@ -129,9 +131,7 @@ Bot.on :optin do |optin|
129
131
  optin.ref # => 'CONTACT_SKYNET'
130
132
 
131
133
  Bot.deliver(
132
- recipient: {
133
- id: '45123'
134
- },
134
+ recipient: optin.sender,
135
135
  message: {
136
136
  text: 'Ah, human!'
137
137
  }
@@ -169,13 +169,24 @@ token of your choosing.
169
169
 
170
170
  Use the generated access token and your verify token to configure your bot:
171
171
 
172
+ ##### ... pass a block, or
173
+
172
174
  ```ruby
173
175
  Facebook::Messenger.configure do |config|
174
176
  config.access_token = 'EAAG6WgW...'
177
+ config.app_secret = '__app_secret_here__'
175
178
  config.verify_token = 'my_voice_is_my_password_verify_me'
176
179
  end
177
180
  ```
178
181
 
182
+ ##### ... set directly
183
+
184
+ ```ruby
185
+ Facebook::Messenger.config.access_token = 'EAAG6WgW...'
186
+ Facebook::Messenger.config.app_secret = '__app_secret_here__'
187
+ Facebook::Messenger.config.verify_token = 'my_voice_is_my_password_verify_me'
188
+ ```
189
+
179
190
  ### Subscribe your Application to a Page
180
191
 
181
192
  Once you've configured your bot, subscribe it to the Page to get messages
@@ -243,11 +254,14 @@ reference constants. You'll need to explicitly load `app/bot`, then:
243
254
 
244
255
  ```ruby
245
256
  # config/initializers/bot.rb
246
- if Rails.env.production?
257
+ unless Rails.env.production?
247
258
  Dir["#{Rails.root}/app/bot/**/*.rb"].each { |file| require file }
248
259
  end
249
260
  ```
250
261
 
262
+ To test your locally running bot, you can use [ngrok]. This will create a secure
263
+ tunnel to localhost so that Facebook can reach the webhook.
264
+
251
265
  ## Development
252
266
 
253
267
  After checking out the repo, run `bin/setup` to install dependencies. You can also run
@@ -280,3 +294,4 @@ If you're using Facebook Messenger, we probably want to [hire you].
280
294
  [developers.facebook.com]: https://developers.facebook.com/
281
295
  [rack]: https://github.com/rack/rack
282
296
  [send-to-messenger-plugin]: https://developers.facebook.com/docs/messenger-platform/plugin-reference
297
+ [ngrok]: https://ngrok.com/
@@ -10,11 +10,15 @@ module Facebook
10
10
  # All the code for this gem resides in this module.
11
11
  module Messenger
12
12
  def self.configure
13
- yield Configuration
13
+ yield config
14
14
  end
15
15
 
16
16
  def self.config
17
- Configuration
17
+ @config ||= Configuration.new
18
+ end
19
+
20
+ def self.config=(config)
21
+ @config = config
18
22
  end
19
23
 
20
24
  configure do |config|
@@ -45,13 +45,13 @@ module Facebook
45
45
  #
46
46
  # * https://developers.facebook.com/docs/messenger-platform/webhook-reference
47
47
  def receive(payload)
48
- klass = Facebook::Messenger::Incoming.parse(payload)
48
+ callback = Facebook::Messenger::Incoming.parse(payload)
49
49
 
50
- case klass
51
- when Incoming::Message then trigger(:message, klass)
52
- when Incoming::Delivery then trigger(:delivery, klass)
53
- when Incoming::Postback then trigger(:postback, klass)
54
- when Incoming::Optin then trigger(:optin, klass)
50
+ case callback
51
+ when Incoming::Message then trigger(:message, callback)
52
+ when Incoming::Delivery then trigger(:delivery, callback)
53
+ when Incoming::Postback then trigger(:postback, callback)
54
+ when Incoming::Optin then trigger(:optin, callback)
55
55
  end
56
56
  end
57
57
 
@@ -1,11 +1,10 @@
1
1
  module Facebook
2
2
  module Messenger
3
3
  # This module holds the configuration.
4
- module Configuration
5
- class << self
6
- attr_accessor :access_token
7
- attr_accessor :verify_token
8
- end
4
+ class Configuration
5
+ attr_accessor :access_token
6
+ attr_accessor :app_secret
7
+ attr_accessor :verify_token
9
8
  end
10
9
  end
11
10
  end
@@ -3,28 +3,30 @@ module Facebook
3
3
  module Incoming
4
4
  # The Delivery class represents the receipt of a delivered message.
5
5
  class Delivery
6
- def initialize(payload)
7
- @payload = payload
6
+ attr_reader :messaging
7
+
8
+ def initialize(messaging)
9
+ @messaging = messaging
8
10
  end
9
11
 
10
12
  def ids
11
- @payload['delivery']['mids']
13
+ @messaging['delivery']['mids']
12
14
  end
13
15
 
14
16
  def at
15
- Time.at(@payload['delivery']['watermark'] / 1000)
17
+ Time.at(@messaging['delivery']['watermark'] / 1000)
16
18
  end
17
19
 
18
20
  def seq
19
- @payload['delivery']['seq']
21
+ @messaging['delivery']['seq']
20
22
  end
21
23
 
22
24
  def sender
23
- @payload['sender']
25
+ @messaging['sender']
24
26
  end
25
27
 
26
28
  def recipient
27
- @payload['recipient']
29
+ @messaging['recipient']
28
30
  end
29
31
  end
30
32
  end
@@ -3,28 +3,34 @@ module Facebook
3
3
  module Incoming
4
4
  # The Message class represents an incoming Facebook Messenger message.
5
5
  class Message
6
- def initialize(payload)
7
- @payload = payload
6
+ attr_reader :messaging
7
+
8
+ def initialize(messaging)
9
+ @messaging = messaging
8
10
  end
9
11
 
10
12
  def id
11
- @payload['message']['mid']
13
+ @messaging['message']['mid']
12
14
  end
13
15
 
14
16
  def sender
15
- @payload['sender']
17
+ @messaging['sender']
16
18
  end
17
19
 
18
20
  def seq
19
- @payload['message']['seq']
21
+ @messaging['message']['seq']
20
22
  end
21
23
 
22
24
  def sent_at
23
- Time.at(@payload['timestamp'] / 1000)
25
+ Time.at(@messaging['timestamp'] / 1000)
24
26
  end
25
27
 
26
28
  def text
27
- @payload['message']['text']
29
+ @messaging['message']['text']
30
+ end
31
+
32
+ def attachments
33
+ @messaging['message']['attachments']
28
34
  end
29
35
  end
30
36
  end
@@ -6,24 +6,26 @@ module Facebook
6
6
  #
7
7
  # https://developers.facebook.com/docs/messenger-platform/plugin-reference
8
8
  class Optin
9
- def initialize(payload)
10
- @payload = payload
9
+ attr_reader :messaging
10
+
11
+ def initialize(messaging)
12
+ @messaging = messaging
11
13
  end
12
14
 
13
15
  def sender
14
- @payload['sender']
16
+ @messaging['sender']
15
17
  end
16
18
 
17
19
  def recipient
18
- @payload['recipient']
20
+ @messaging['recipient']
19
21
  end
20
22
 
21
23
  def sent_at
22
- Time.at(@payload['timestamp'] / 1000)
24
+ Time.at(@messaging['timestamp'] / 1000)
23
25
  end
24
26
 
25
27
  def ref
26
- @payload['optin']['ref']
28
+ @messaging['optin']['ref']
27
29
  end
28
30
  end
29
31
  end
@@ -3,24 +3,26 @@ module Facebook
3
3
  module Incoming
4
4
  # The Postback class represents an incoming Facebook Messenger postback.
5
5
  class Postback
6
- def initialize(payload)
7
- @payload = payload
6
+ attr_reader :messaging
7
+
8
+ def initialize(messaging)
9
+ @messaging = messaging
8
10
  end
9
11
 
10
12
  def sender
11
- @payload['sender']
13
+ @messaging['sender']
12
14
  end
13
15
 
14
16
  def recipient
15
- @payload['recipient']
17
+ @messaging['recipient']
16
18
  end
17
19
 
18
20
  def sent_at
19
- Time.at(@payload['timestamp'] / 1000)
21
+ Time.at(@messaging['timestamp'] / 1000)
20
22
  end
21
23
 
22
24
  def payload
23
- @payload['postback']['payload']
25
+ @messaging['postback']['payload']
24
26
  end
25
27
  end
26
28
  end
@@ -1,5 +1,6 @@
1
1
  require 'rack'
2
2
  require 'json'
3
+ require 'openssl'
3
4
 
4
5
  module Facebook
5
6
  module Messenger
@@ -14,18 +15,19 @@ module Facebook
14
15
  @request = Rack::Request.new(env)
15
16
  @response = Rack::Response.new
16
17
 
17
- case
18
- when @request.get? then verify
19
- when @request.post? then receive
18
+ if @request.get? then verify
19
+ elsif @request.post? then receive
20
20
  else @response.status = 405
21
21
  end
22
22
 
23
23
  @response.finish
24
24
  end
25
25
 
26
+ private
27
+
26
28
  def verify
27
- if @request['hub.verify_token'] == verify_token
28
- @response.write @request['hub.challenge']
29
+ if @request.params['hub.verify_token'] == verify_token
30
+ @response.write @request.params['hub.challenge']
29
31
  else
30
32
  @response.write 'Error; wrong verify token'
31
33
  end
@@ -36,6 +38,8 @@ module Facebook
36
38
  end
37
39
 
38
40
  def receive
41
+ return if app_secret && !integrity?
42
+
39
43
  hash = JSON.parse(@request.body.read)
40
44
 
41
45
  # Facebook may batch several items in the 'entry' array during
@@ -48,6 +52,32 @@ module Facebook
48
52
  end
49
53
  end
50
54
  end
55
+
56
+ def integrity?
57
+ Rack::Utils.secure_compare(x_hub_signature, signature)
58
+ end
59
+
60
+ def x_hub_signature
61
+ @request.env['HTTP_X_HUB_SIGNATURE'.freeze]
62
+ end
63
+
64
+ def signature
65
+ format('sha1=%s'.freeze, generate_hmac(@request.body.read))
66
+ ensure
67
+ @request.body.rewind
68
+ end
69
+
70
+ def generate_hmac(content)
71
+ OpenSSL::HMAC.hexdigest(
72
+ OpenSSL::Digest.new('sha1'),
73
+ app_secret,
74
+ content
75
+ )
76
+ end
77
+
78
+ def app_secret
79
+ Facebook::Messenger.config.app_secret
80
+ end
51
81
  end
52
82
  end
53
83
  end
@@ -8,30 +8,38 @@ module Facebook
8
8
 
9
9
  base_uri 'https://graph.facebook.com/v2.6/me'
10
10
 
11
- def self.subscribe
12
- response = post '/subscribed_apps', format: :json, query: {
13
- access_token: Facebook::Messenger.config.access_token
14
- }
11
+ format :json
12
+
13
+ module_function
14
+
15
+ def subscribe
16
+ response = post '/subscribed_apps'
15
17
 
16
18
  raise_errors(response)
17
19
 
18
20
  true
19
21
  end
20
22
 
21
- def self.unsubscribe
22
- response = delete '/subscribed_apps', format: :json, query: {
23
- access_token: Facebook::Messenger.config.access_token
24
- }
23
+ def unsubscribe
24
+ response = delete '/subscribed_apps'
25
25
 
26
26
  raise_errors(response)
27
27
 
28
28
  true
29
29
  end
30
30
 
31
- def self.raise_errors(response)
31
+ def raise_errors(response)
32
32
  raise Error, response['error']['message'] if response.key? 'error'
33
33
  end
34
34
 
35
+ def default_options
36
+ super.merge(
37
+ query: {
38
+ access_token: Facebook::Messenger.config.access_token
39
+ }
40
+ )
41
+ end
42
+
35
43
  class Error < Facebook::Messenger::Error; end
36
44
  end
37
45
  end
@@ -1,5 +1,5 @@
1
1
  module Facebook
2
2
  module Messenger
3
- VERSION = '0.4.2'.freeze
3
+ VERSION = '0.5.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facebook-messenger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes Gorset
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-05-02 00:00:00.000000000 Z
11
+ date: 2016-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -28,14 +28,14 @@ dependencies:
28
28
  name: rack
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.6.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.6.4
41
41
  - !ruby/object:Gem::Dependency