facebook-messenger 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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