facebook-messenger 0.10.0 → 0.11.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 +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
|