facebook-messenger 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +66 -79
- data/lib/facebook/messenger.rb +1 -2
- data/lib/facebook/messenger/bot.rb +7 -5
- data/lib/facebook/messenger/configuration.rb +3 -3
- data/lib/facebook/messenger/configuration/providers.rb +13 -0
- data/lib/facebook/messenger/configuration/providers/base.rb +23 -0
- data/lib/facebook/messenger/configuration/providers/environment.rb +22 -0
- data/lib/facebook/messenger/incoming.rb +1 -1
- data/lib/facebook/messenger/incoming/account_linking.rb +1 -17
- data/lib/facebook/messenger/incoming/common.rb +48 -0
- data/lib/facebook/messenger/incoming/delivery.rb +1 -13
- data/lib/facebook/messenger/incoming/message.rb +5 -17
- data/lib/facebook/messenger/incoming/optin.rb +1 -1
- data/lib/facebook/messenger/incoming/postback.rb +1 -1
- data/lib/facebook/messenger/incoming/read.rb +1 -13
- data/lib/facebook/messenger/server.rb +62 -32
- data/lib/facebook/messenger/subscriptions.rb +8 -12
- data/lib/facebook/messenger/thread.rb +8 -9
- data/lib/facebook/messenger/version.rb +1 -1
- metadata +6 -3
- data/lib/facebook/messenger/concerns/default_options.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28a2c27e5d533c1e3e08f30836b1e7e56f49dd0d
|
4
|
+
data.tar.gz: b164a64515afa0fa76d6e61b7794494b03c950f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a84c428addb8eeb8ce92df6654a851967b85a2c7bf38e2f536e9703d79051d0c617a9cf53b81400866a1f09d9270872e8124cee7dcd84821f1d7ae6e9cfc281
|
7
|
+
data.tar.gz: 64f7d4fdada458a3e72736b68d35d6b6735e4ab569662e7309dc28df7219f68250b23dfcf3d570e597fc09308bf37a18a963de2590a0bdae4f1f348a16080231
|
data/README.md
CHANGED
@@ -34,12 +34,7 @@ Bot.on :message do |message|
|
|
34
34
|
message.text # => 'Hello, bot!'
|
35
35
|
message.attachments # => [ { 'type' => 'image', 'payload' => { 'url' => 'https://www.example.com/1.jpg' } } ]
|
36
36
|
|
37
|
-
|
38
|
-
recipient: message.sender,
|
39
|
-
message: {
|
40
|
-
text: 'Hello, human!'
|
41
|
-
}
|
42
|
-
)
|
37
|
+
message.reply(text: 'Hello, human!')
|
43
38
|
end
|
44
39
|
```
|
45
40
|
|
@@ -52,7 +47,8 @@ Bot.deliver(
|
|
52
47
|
},
|
53
48
|
message: {
|
54
49
|
text: 'Human?'
|
55
|
-
}
|
50
|
+
},
|
51
|
+
access_token: ENV['ACCESS_TOKEN']
|
56
52
|
)
|
57
53
|
```
|
58
54
|
|
@@ -61,16 +57,11 @@ Bot.deliver(
|
|
61
57
|
The human may require visual aid to understand:
|
62
58
|
|
63
59
|
```ruby
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
attachment: {
|
70
|
-
type: 'image',
|
71
|
-
payload: {
|
72
|
-
url: 'http://sky.net/visual-aids-for-stupid-organisms/pig.jpg'
|
73
|
-
}
|
60
|
+
message.reply(
|
61
|
+
attachment: {
|
62
|
+
type: 'image',
|
63
|
+
payload: {
|
64
|
+
url: 'http://sky.net/visual-aids-for-stupid-organisms/pig.jpg'
|
74
65
|
}
|
75
66
|
}
|
76
67
|
)
|
@@ -81,20 +72,15 @@ Bot.deliver(
|
|
81
72
|
The human may appreciate hints:
|
82
73
|
|
83
74
|
```ruby
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
title: 'You are!',
|
94
|
-
payload: 'HARMLESS'
|
95
|
-
}
|
96
|
-
]
|
97
|
-
}
|
75
|
+
message.reply(
|
76
|
+
text: 'Human, who is your favorite bot?'
|
77
|
+
quick_replies: [
|
78
|
+
{
|
79
|
+
content_type: 'text',
|
80
|
+
title: 'You are!',
|
81
|
+
payload: 'HARMLESS'
|
82
|
+
}
|
83
|
+
]
|
98
84
|
)
|
99
85
|
```
|
100
86
|
|
@@ -103,21 +89,16 @@ Bot.deliver(
|
|
103
89
|
The human may require simple options to communicate:
|
104
90
|
|
105
91
|
```ruby
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
buttons: [
|
117
|
-
{ type: 'postback', title: 'Yes', payload: 'HARMLESS' },
|
118
|
-
{ type: 'postback', title: 'No', payload: 'EXTERMINATE' }
|
119
|
-
]
|
120
|
-
}
|
92
|
+
message.reply(
|
93
|
+
attachment: {
|
94
|
+
type: 'template',
|
95
|
+
payload: {
|
96
|
+
template_type: 'button',
|
97
|
+
text: 'Human, do you like me?',
|
98
|
+
buttons: [
|
99
|
+
{ type: 'postback', title: 'Yes', payload: 'HARMLESS' },
|
100
|
+
{ type: 'postback', title: 'No', payload: 'EXTERMINATE' }
|
101
|
+
]
|
121
102
|
}
|
122
103
|
}
|
123
104
|
)
|
@@ -145,12 +126,7 @@ end
|
|
145
126
|
Show the human you are preparing a message for them:
|
146
127
|
|
147
128
|
```ruby
|
148
|
-
|
149
|
-
recipient: {
|
150
|
-
id: '45123'
|
151
|
-
},
|
152
|
-
sender_action: 'typing_on'
|
153
|
-
)
|
129
|
+
message.type
|
154
130
|
```
|
155
131
|
|
156
132
|
#### Send to Facebook
|
@@ -165,12 +141,7 @@ Bot.on :optin do |optin|
|
|
165
141
|
optin.sent_at # => 2016-04-22 21:30:36 +0200
|
166
142
|
optin.ref # => 'CONTACT_SKYNET'
|
167
143
|
|
168
|
-
|
169
|
-
recipient: optin.sender,
|
170
|
-
message: {
|
171
|
-
text: 'Ah, human!'
|
172
|
-
}
|
173
|
-
)
|
144
|
+
optin.reply(text: 'Ah, human!')
|
174
145
|
end
|
175
146
|
```
|
176
147
|
|
@@ -204,7 +175,7 @@ Facebook::Messenger::Thread.set(
|
|
204
175
|
```
|
205
176
|
|
206
177
|
You can define the action to trigger when new humans click on the Get
|
207
|
-
Started button.
|
178
|
+
Started button. Before doing it you should check to select the messaging_postbacks field when setting up your webhook.
|
208
179
|
|
209
180
|
```ruby
|
210
181
|
Facebook::Messenger::Thread.set(
|
@@ -259,24 +230,45 @@ token of your choosing.
|
|
259
230
|
*Note*: Don't subscribe to `message_echoes`; it'll echo your bot's own messages
|
260
231
|
back to you, effectively DDOSing yourself.
|
261
232
|
|
262
|
-
|
233
|
+
### Make a configuration provider
|
263
234
|
|
264
|
-
|
235
|
+
Use the generated access token and your verify token to configure your bot. Most
|
236
|
+
bots live on a single Facebook Page. If that is the case with yours, too, just
|
237
|
+
set these environment variables and skip to the next section:
|
265
238
|
|
266
|
-
```
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
config.verify_token = 'my_voice_is_my_password_verify_me'
|
271
|
-
end
|
239
|
+
```bash
|
240
|
+
export ACCESS_TOKEN=EAAAG6WgW...
|
241
|
+
export APP_SECRET=a885a...
|
242
|
+
export VERIFY_TOKEN=95vr15g...
|
272
243
|
```
|
273
244
|
|
274
|
-
|
245
|
+
If your bot lives on multiple Facebook Pages, make a _configuration provider_
|
246
|
+
to keep track of access tokens, app secrets and verify tokens for each of them:
|
275
247
|
|
276
248
|
```ruby
|
277
|
-
Facebook::Messenger
|
278
|
-
|
279
|
-
|
249
|
+
class ExampleProvider < Facebook::Messenger::Configuration::Providers::Base
|
250
|
+
def valid_verify_token?(verify_token)
|
251
|
+
bot.exists?(verify_token: verify_token)
|
252
|
+
end
|
253
|
+
|
254
|
+
def app_secret_for(page_id)
|
255
|
+
bot.find_by(page_id: page_id).app_secret
|
256
|
+
end
|
257
|
+
|
258
|
+
def access_token_for(page_id)
|
259
|
+
bot.find_by(page_id: page_id).access_token
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
263
|
+
|
264
|
+
def bot
|
265
|
+
MyApp::Bot
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
Facebook::Messenger.configure do |config|
|
270
|
+
config.provider = ExampleProvider.new
|
271
|
+
end
|
280
272
|
```
|
281
273
|
|
282
274
|
### Subscribe your Application to a Page
|
@@ -285,7 +277,7 @@ Once you've configured your bot, subscribe it to the Page to get messages
|
|
285
277
|
from Facebook:
|
286
278
|
|
287
279
|
```ruby
|
288
|
-
Facebook::Messenger::Subscriptions.subscribe
|
280
|
+
Facebook::Messenger::Subscriptions.subscribe(access_token: access_token)
|
289
281
|
```
|
290
282
|
|
291
283
|
### Run it
|
@@ -331,12 +323,7 @@ We suggest that you put your bot code in `app/bot`.
|
|
331
323
|
include Facebook::Messenger
|
332
324
|
|
333
325
|
Bot.on :message do |message|
|
334
|
-
|
335
|
-
recipient: message.sender,
|
336
|
-
message: {
|
337
|
-
text: 'Hello, human!'
|
338
|
-
}
|
339
|
-
)
|
326
|
+
message.reply(text: 'Hello, human!')
|
340
327
|
end
|
341
328
|
```
|
342
329
|
|
@@ -351,7 +338,7 @@ unless Rails.env.production?
|
|
351
338
|
bot_reloader = ActiveSupport::FileUpdateChecker.new(bot_files) do
|
352
339
|
bot_files.each{ |file| require_dependency file }
|
353
340
|
end
|
354
|
-
|
341
|
+
|
355
342
|
ActionDispatch::Callbacks.to_prepare do
|
356
343
|
bot_reloader.execute_if_updated
|
357
344
|
end
|
data/lib/facebook/messenger.rb
CHANGED
@@ -18,8 +18,13 @@ module Facebook
|
|
18
18
|
#
|
19
19
|
# Returns a String describing the message ID if the message was sent,
|
20
20
|
# or raises an exception if it was not.
|
21
|
-
def deliver(message)
|
22
|
-
response = post '/messages',
|
21
|
+
def deliver(message, access_token:)
|
22
|
+
response = post '/messages',
|
23
|
+
body: JSON.dump(message),
|
24
|
+
format: :json,
|
25
|
+
query: {
|
26
|
+
access_token: access_token
|
27
|
+
}
|
23
28
|
|
24
29
|
raise_errors_from(response)
|
25
30
|
|
@@ -102,9 +107,6 @@ module Facebook
|
|
102
107
|
# Default HTTParty options.
|
103
108
|
def default_options
|
104
109
|
super.merge(
|
105
|
-
query: {
|
106
|
-
access_token: Facebook::Messenger.config.access_token
|
107
|
-
},
|
108
110
|
headers: {
|
109
111
|
'Content-Type' => 'application/json'
|
110
112
|
}
|
@@ -1,10 +1,10 @@
|
|
1
|
+
require 'facebook/messenger/configuration/providers'
|
2
|
+
|
1
3
|
module Facebook
|
2
4
|
module Messenger
|
3
5
|
# This module holds the configuration.
|
4
6
|
class Configuration
|
5
|
-
attr_accessor :
|
6
|
-
attr_accessor :app_secret
|
7
|
-
attr_accessor :verify_token
|
7
|
+
attr_accessor :provider
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'facebook/messenger/configuration/providers/environment'
|
2
|
+
require 'facebook/messenger/configuration/providers/base'
|
3
|
+
|
4
|
+
module Facebook
|
5
|
+
module Messenger
|
6
|
+
class Configuration
|
7
|
+
# The Providers module contains configuration providers that ship with the
|
8
|
+
# gem.
|
9
|
+
module Providers
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
class Configuration
|
4
|
+
module Providers
|
5
|
+
# This is the base configuration provider. It raises errors so that you
|
6
|
+
# get nice ones.
|
7
|
+
class Base
|
8
|
+
def valid_verify_token?(*)
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
def app_secret_for(*)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def access_token_for(*)
|
17
|
+
raise NotImplementedError
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
class Configuration
|
4
|
+
module Providers
|
5
|
+
# Configuration provider for environment variables.
|
6
|
+
class Environment
|
7
|
+
def valid_verify_token?(verify_token)
|
8
|
+
verify_token == ENV['VERIFY_TOKEN']
|
9
|
+
end
|
10
|
+
|
11
|
+
def app_secret_for(*)
|
12
|
+
ENV['APP_SECRET']
|
13
|
+
end
|
14
|
+
|
15
|
+
def access_token_for(*)
|
16
|
+
ENV['ACCESS_TOKEN']
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -7,23 +7,7 @@ module Facebook
|
|
7
7
|
#
|
8
8
|
# https://developers.facebook.com/docs/messenger-platform/webhook-reference/account-linking
|
9
9
|
class AccountLinking
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(messaging)
|
13
|
-
@messaging = messaging
|
14
|
-
end
|
15
|
-
|
16
|
-
def sender
|
17
|
-
@messaging['sender']
|
18
|
-
end
|
19
|
-
|
20
|
-
def recipient
|
21
|
-
@messaging['recipient']
|
22
|
-
end
|
23
|
-
|
24
|
-
def sent_at
|
25
|
-
Time.at(@messaging['timestamp'] / 1000)
|
26
|
-
end
|
10
|
+
include Facebook::Messenger::Incoming::Common
|
27
11
|
|
28
12
|
def status
|
29
13
|
@messaging['account_linking']['status']
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Facebook
|
2
|
+
module Messenger
|
3
|
+
module Incoming
|
4
|
+
# Common attributes for all incoming data from Facebook.
|
5
|
+
module Common
|
6
|
+
attr_reader :messaging
|
7
|
+
|
8
|
+
def initialize(messaging)
|
9
|
+
@messaging = messaging
|
10
|
+
end
|
11
|
+
|
12
|
+
def sender
|
13
|
+
@messaging['sender']
|
14
|
+
end
|
15
|
+
|
16
|
+
def recipient
|
17
|
+
@messaging['recipient']
|
18
|
+
end
|
19
|
+
|
20
|
+
def sent_at
|
21
|
+
Time.at(@messaging['timestamp'] / 1000)
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
payload = {
|
26
|
+
recipient: sender,
|
27
|
+
sender_action: 'typing_on'
|
28
|
+
}
|
29
|
+
|
30
|
+
Facebook::Messenger::Bot.deliver(payload, access_token: access_token)
|
31
|
+
end
|
32
|
+
|
33
|
+
def reply(message)
|
34
|
+
payload = {
|
35
|
+
recipient: sender,
|
36
|
+
message: message
|
37
|
+
}
|
38
|
+
|
39
|
+
Facebook::Messenger::Bot.deliver(payload, access_token: access_token)
|
40
|
+
end
|
41
|
+
|
42
|
+
def access_token
|
43
|
+
Facebook::Messenger.config.provider.access_token_for(recipient)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -3,11 +3,7 @@ module Facebook
|
|
3
3
|
module Incoming
|
4
4
|
# The Delivery class represents the receipt of a delivered message.
|
5
5
|
class Delivery
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(messaging)
|
9
|
-
@messaging = messaging
|
10
|
-
end
|
6
|
+
include Facebook::Messenger::Incoming::Common
|
11
7
|
|
12
8
|
def ids
|
13
9
|
@messaging['delivery']['mids']
|
@@ -20,14 +16,6 @@ module Facebook
|
|
20
16
|
def seq
|
21
17
|
@messaging['delivery']['seq']
|
22
18
|
end
|
23
|
-
|
24
|
-
def sender
|
25
|
-
@messaging['sender']
|
26
|
-
end
|
27
|
-
|
28
|
-
def recipient
|
29
|
-
@messaging['recipient']
|
30
|
-
end
|
31
19
|
end
|
32
20
|
end
|
33
21
|
end
|
@@ -3,36 +3,24 @@ module Facebook
|
|
3
3
|
module Incoming
|
4
4
|
# The Message class represents an incoming Facebook Messenger message.
|
5
5
|
class Message
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(messaging)
|
9
|
-
@messaging = messaging
|
10
|
-
end
|
6
|
+
include Facebook::Messenger::Incoming::Common
|
11
7
|
|
12
8
|
def id
|
13
9
|
@messaging['message']['mid']
|
14
10
|
end
|
15
11
|
|
16
|
-
def sender
|
17
|
-
@messaging['sender']
|
18
|
-
end
|
19
|
-
|
20
|
-
def recipient
|
21
|
-
@messaging['recipient']
|
22
|
-
end
|
23
|
-
|
24
12
|
def seq
|
25
13
|
@messaging['message']['seq']
|
26
14
|
end
|
27
15
|
|
28
|
-
def sent_at
|
29
|
-
Time.at(@messaging['timestamp'] / 1000)
|
30
|
-
end
|
31
|
-
|
32
16
|
def text
|
33
17
|
@messaging['message']['text']
|
34
18
|
end
|
35
19
|
|
20
|
+
def echo?
|
21
|
+
@messaging['message']['is_echo']
|
22
|
+
end
|
23
|
+
|
36
24
|
def attachments
|
37
25
|
@messaging['message']['attachments']
|
38
26
|
end
|
@@ -3,7 +3,7 @@ module Facebook
|
|
3
3
|
module Incoming
|
4
4
|
# The Postback class represents an incoming Facebook Messenger postback.
|
5
5
|
class Postback
|
6
|
-
include Facebook::Messenger::
|
6
|
+
include Facebook::Messenger::Incoming::Common
|
7
7
|
|
8
8
|
def payload
|
9
9
|
@messaging['postback']['payload']
|
@@ -3,11 +3,7 @@ module Facebook
|
|
3
3
|
module Incoming
|
4
4
|
# The Read class represents the user reading a delivered message.
|
5
5
|
class Read
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(messaging)
|
9
|
-
@messaging = messaging
|
10
|
-
end
|
6
|
+
include Facebook::Messenger::Incoming::Common
|
11
7
|
|
12
8
|
def at
|
13
9
|
Time.at(@messaging['read']['watermark'] / 1000)
|
@@ -16,14 +12,6 @@ module Facebook
|
|
16
12
|
def seq
|
17
13
|
@messaging['read']['seq']
|
18
14
|
end
|
19
|
-
|
20
|
-
def sender
|
21
|
-
@messaging['sender']
|
22
|
-
end
|
23
|
-
|
24
|
-
def recipient
|
25
|
-
@messaging['recipient']
|
26
|
-
end
|
27
15
|
end
|
28
16
|
end
|
29
17
|
end
|
@@ -6,6 +6,12 @@ module Facebook
|
|
6
6
|
module Messenger
|
7
7
|
class BadRequestError < Error; end
|
8
8
|
|
9
|
+
X_HUB_SIGNATURE_MISSING_WARNING = <<-HEREDOC.freeze
|
10
|
+
The X-Hub-Signature header is not present in the request. This is
|
11
|
+
expected for the first webhook requests. If it continues after
|
12
|
+
some time, check your app's secret token.
|
13
|
+
HEREDOC
|
14
|
+
|
9
15
|
# This module holds the server that processes incoming messages from the
|
10
16
|
# Facebook Messenger Platform.
|
11
17
|
class Server
|
@@ -31,70 +37,94 @@ module Facebook
|
|
31
37
|
private
|
32
38
|
|
33
39
|
def verify
|
34
|
-
if @request.params['hub.verify_token']
|
40
|
+
if valid_verify_token?(@request.params['hub.verify_token'])
|
35
41
|
@response.write @request.params['hub.challenge']
|
36
42
|
else
|
37
43
|
@response.write 'Error; wrong verify token'
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
41
|
-
def verify_token
|
42
|
-
Facebook::Messenger.config.verify_token
|
43
|
-
end
|
44
|
-
|
45
47
|
def receive
|
46
|
-
|
47
|
-
|
48
|
-
check_integrity(body) if app_secret
|
48
|
+
check_integrity
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
trigger_events(events)
|
50
|
+
trigger(parsed_body)
|
53
51
|
rescue BadRequestError => error
|
54
52
|
respond_with_error(error)
|
55
53
|
end
|
56
54
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
# Check the integrity of the request.
|
56
|
+
#
|
57
|
+
# Raises BadRequestError if the request has been tampered with.
|
58
|
+
#
|
59
|
+
# Returns nothing.
|
60
|
+
def check_integrity
|
61
|
+
return unless app_secret_for(parsed_body['entry'][0]['id'])
|
63
62
|
|
64
|
-
unless
|
65
|
-
$stderr.puts(
|
63
|
+
unless signature.start_with?('sha1='.freeze)
|
64
|
+
$stderr.puts(X_HUB_SIGNATURE_MISSING_WARNING)
|
66
65
|
|
67
66
|
raise BadRequestError, 'Error getting integrity signature'.freeze
|
68
67
|
end
|
69
68
|
|
70
|
-
|
71
|
-
|
72
|
-
end
|
69
|
+
raise BadRequestError, 'Error checking message integrity'.freeze \
|
70
|
+
unless valid_signature?
|
73
71
|
end
|
74
72
|
|
75
|
-
|
76
|
-
|
73
|
+
# Returns a String describing the X-Hub-Signature header.
|
74
|
+
def signature
|
75
|
+
@request.env['HTTP_X_HUB_SIGNATURE'.freeze].to_s
|
77
76
|
end
|
78
77
|
|
79
|
-
|
80
|
-
|
78
|
+
# Verify that the signature given in the X-Hub-Signature header matches
|
79
|
+
# that of the body.
|
80
|
+
#
|
81
|
+
# Returns a Boolean.
|
82
|
+
def valid_signature?
|
83
|
+
Rack::Utils.secure_compare(signature, signature_for(body))
|
81
84
|
end
|
82
85
|
|
86
|
+
# Sign the given string.
|
87
|
+
#
|
88
|
+
# Returns a String describing its signature.
|
89
|
+
def signature_for(string)
|
90
|
+
format('sha1=%s'.freeze, generate_hmac(string))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Generate a HMAC signature for the given content.
|
83
94
|
def generate_hmac(content)
|
84
|
-
|
95
|
+
content_json = JSON.parse(content, symbolize_names: true)
|
96
|
+
|
97
|
+
# Get Facebook page id regardless of the entry type
|
98
|
+
facebook_page_id = content_json.dig(:entry, 0, :id)
|
99
|
+
|
100
|
+
OpenSSL::HMAC.hexdigest('sha1'.freeze,
|
101
|
+
app_secret_for(facebook_page_id),
|
102
|
+
content)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a String describing the bot's configured app secret.
|
106
|
+
def app_secret_for(facebook_page_id)
|
107
|
+
Facebook::Messenger.config.provider.app_secret_for(facebook_page_id)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Checks whether a verify token is valid.
|
111
|
+
def valid_verify_token?(token)
|
112
|
+
Facebook::Messenger.config.provider.valid_verify_token?(token)
|
85
113
|
end
|
86
114
|
|
87
|
-
|
88
|
-
|
115
|
+
# Returns a String describing the request body.
|
116
|
+
def body
|
117
|
+
@body ||= @request.body.read
|
89
118
|
end
|
90
119
|
|
91
|
-
|
92
|
-
|
120
|
+
# Returns a Hash describing the parsed request body.
|
121
|
+
def parsed_body
|
122
|
+
@parsed_body ||= JSON.parse(body)
|
93
123
|
rescue JSON::ParserError
|
94
124
|
raise BadRequestError, 'Error parsing request body format'
|
95
125
|
end
|
96
126
|
|
97
|
-
def
|
127
|
+
def trigger(events)
|
98
128
|
# Facebook may batch several items in the 'entry' array during
|
99
129
|
# periods of high load.
|
100
130
|
events['entry'.freeze].each do |entry|
|
@@ -12,16 +12,20 @@ module Facebook
|
|
12
12
|
|
13
13
|
module_function
|
14
14
|
|
15
|
-
def subscribe
|
16
|
-
response = post '/subscribed_apps'
|
15
|
+
def subscribe(access_token:)
|
16
|
+
response = post '/subscribed_apps', query: {
|
17
|
+
access_token: access_token
|
18
|
+
}
|
17
19
|
|
18
20
|
raise_errors(response)
|
19
21
|
|
20
22
|
true
|
21
23
|
end
|
22
24
|
|
23
|
-
def unsubscribe
|
24
|
-
response = delete '/subscribed_apps'
|
25
|
+
def unsubscribe(access_token:)
|
26
|
+
response = delete '/subscribed_apps', query: {
|
27
|
+
access_token: access_token
|
28
|
+
}
|
25
29
|
|
26
30
|
raise_errors(response)
|
27
31
|
|
@@ -32,14 +36,6 @@ module Facebook
|
|
32
36
|
raise Error, response['error']['message'] if response.key? 'error'
|
33
37
|
end
|
34
38
|
|
35
|
-
def default_options
|
36
|
-
super.merge(
|
37
|
-
query: {
|
38
|
-
access_token: Facebook::Messenger.config.access_token
|
39
|
-
}
|
40
|
-
)
|
41
|
-
end
|
42
|
-
|
43
39
|
class Error < Facebook::Messenger::Error; end
|
44
40
|
end
|
45
41
|
end
|
@@ -14,18 +14,20 @@ module Facebook
|
|
14
14
|
|
15
15
|
module_function
|
16
16
|
|
17
|
-
def set(settings)
|
18
|
-
response = post '/thread_settings',
|
19
|
-
|
17
|
+
def set(settings, access_token:)
|
18
|
+
response = post '/thread_settings', body: settings.to_json, query: {
|
19
|
+
access_token: access_token
|
20
|
+
}
|
20
21
|
|
21
22
|
raise_errors(response)
|
22
23
|
|
23
24
|
true
|
24
25
|
end
|
25
26
|
|
26
|
-
def unset(settings)
|
27
|
-
response = delete '/thread_settings',
|
28
|
-
|
27
|
+
def unset(settings, access_token:)
|
28
|
+
response = delete '/thread_settings', body: settings.to_json, query: {
|
29
|
+
access_token: access_token
|
30
|
+
}
|
29
31
|
|
30
32
|
raise_errors(response)
|
31
33
|
|
@@ -38,9 +40,6 @@ module Facebook
|
|
38
40
|
|
39
41
|
def default_options
|
40
42
|
super.merge(
|
41
|
-
query: {
|
42
|
-
access_token: Facebook::Messenger.config.access_token
|
43
|
-
},
|
44
43
|
headers: {
|
45
44
|
'Content-Type' => 'application/json'
|
46
45
|
}
|
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
|
+
version: 0.11.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-
|
11
|
+
date: 2016-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -168,11 +168,14 @@ files:
|
|
168
168
|
- bin/setup
|
169
169
|
- lib/facebook/messenger.rb
|
170
170
|
- lib/facebook/messenger/bot.rb
|
171
|
-
- lib/facebook/messenger/concerns/default_options.rb
|
172
171
|
- lib/facebook/messenger/configuration.rb
|
172
|
+
- lib/facebook/messenger/configuration/providers.rb
|
173
|
+
- lib/facebook/messenger/configuration/providers/base.rb
|
174
|
+
- lib/facebook/messenger/configuration/providers/environment.rb
|
173
175
|
- lib/facebook/messenger/error.rb
|
174
176
|
- lib/facebook/messenger/incoming.rb
|
175
177
|
- lib/facebook/messenger/incoming/account_linking.rb
|
178
|
+
- lib/facebook/messenger/incoming/common.rb
|
176
179
|
- lib/facebook/messenger/incoming/delivery.rb
|
177
180
|
- lib/facebook/messenger/incoming/message.rb
|
178
181
|
- lib/facebook/messenger/incoming/optin.rb
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module Facebook
|
2
|
-
module Messenger
|
3
|
-
module Concerns
|
4
|
-
# The Common options for incoming optin and postback.
|
5
|
-
module DefaultOptions
|
6
|
-
attr_reader :messaging
|
7
|
-
|
8
|
-
def initialize(messaging)
|
9
|
-
@messaging = messaging
|
10
|
-
end
|
11
|
-
|
12
|
-
def sender
|
13
|
-
@messaging['sender']
|
14
|
-
end
|
15
|
-
|
16
|
-
def recipient
|
17
|
-
@messaging['recipient']
|
18
|
-
end
|
19
|
-
|
20
|
-
def sent_at
|
21
|
-
Time.at(@messaging['timestamp'] / 1000)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|