slack-ruby-client 0.12.0 → 0.14.6

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.
Files changed (301) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +21 -9
  4. data/.rubocop_todo.yml +64 -56
  5. data/.travis.yml +5 -3
  6. data/CHANGELOG.md +90 -32
  7. data/Dangerfile +2 -0
  8. data/Gemfile +10 -4
  9. data/LICENSE.md +1 -1
  10. data/README.md +176 -32
  11. data/Rakefile +2 -1
  12. data/UPGRADING.md +27 -1
  13. data/bin/commands.rb +21 -0
  14. data/bin/commands/admin_apps.rb +27 -0
  15. data/bin/commands/admin_apps_approved.rb +17 -0
  16. data/bin/commands/admin_apps_requests.rb +16 -0
  17. data/bin/commands/admin_apps_restricted.rb +17 -0
  18. data/bin/commands/admin_conversations.rb +17 -0
  19. data/bin/commands/admin_emoji.rb +54 -0
  20. data/bin/commands/admin_inviteRequests.rb +36 -0
  21. data/bin/commands/admin_inviteRequests_approved.rb +16 -0
  22. data/bin/commands/admin_inviteRequests_denied.rb +16 -0
  23. data/bin/commands/admin_teams.rb +27 -0
  24. data/bin/commands/admin_teams_admins.rb +16 -0
  25. data/bin/commands/admin_teams_owners.rb +16 -0
  26. data/bin/commands/admin_teams_settings.rb +64 -0
  27. data/bin/commands/admin_users.rb +97 -0
  28. data/bin/commands/admin_users_session.rb +16 -0
  29. data/bin/commands/api.rb +1 -0
  30. data/bin/commands/apps.rb +15 -0
  31. data/bin/commands/apps_permissions.rb +1 -0
  32. data/bin/commands/apps_permissions_resources.rb +1 -0
  33. data/bin/commands/apps_permissions_scopes.rb +1 -0
  34. data/bin/commands/apps_permissions_users.rb +1 -0
  35. data/bin/commands/auth.rb +1 -0
  36. data/bin/commands/bots.rb +1 -0
  37. data/bin/commands/channels.rb +3 -1
  38. data/bin/commands/chat.rb +48 -9
  39. data/bin/commands/chat_scheduledMessages.rb +18 -0
  40. data/bin/commands/conversations.rb +4 -2
  41. data/bin/commands/dialog.rb +1 -0
  42. data/bin/commands/dnd.rb +4 -3
  43. data/bin/commands/emoji.rb +1 -0
  44. data/bin/commands/files.rb +4 -14
  45. data/bin/commands/files_comments.rb +1 -21
  46. data/bin/commands/files_remote.rb +78 -0
  47. data/bin/commands/groups.rb +2 -1
  48. data/bin/commands/im.rb +2 -1
  49. data/bin/commands/migration.rb +1 -0
  50. data/bin/commands/mpim.rb +2 -1
  51. data/bin/commands/oauth.rb +2 -1
  52. data/bin/commands/oauth_v2.rb +17 -0
  53. data/bin/commands/pins.rb +1 -2
  54. data/bin/commands/reactions.rb +2 -3
  55. data/bin/commands/reminders.rb +1 -0
  56. data/bin/commands/rtm.rb +1 -0
  57. data/bin/commands/search.rb +2 -1
  58. data/bin/commands/stars.rb +1 -0
  59. data/bin/commands/team.rb +2 -0
  60. data/bin/commands/team_profile.rb +1 -0
  61. data/bin/commands/usergroups.rb +2 -1
  62. data/bin/commands/usergroups_users.rb +1 -0
  63. data/bin/commands/users.rb +2 -2
  64. data/bin/commands/users_admin.rb +1 -0
  65. data/bin/commands/users_prefs.rb +1 -0
  66. data/bin/commands/users_profile.rb +1 -0
  67. data/bin/commands/views.rb +48 -0
  68. data/bin/slack +2 -3
  69. data/examples/hi_real_time/Gemfile +1 -0
  70. data/examples/hi_real_time/hi.rb +7 -3
  71. data/examples/hi_real_time_and_web/Gemfile +1 -0
  72. data/examples/hi_real_time_and_web/hi.rb +7 -3
  73. data/examples/hi_real_time_async_async/Gemfile +7 -0
  74. data/examples/hi_real_time_async_async/Procfile +2 -0
  75. data/examples/hi_real_time_async_async/hi.rb +41 -0
  76. data/examples/hi_real_time_async_celluloid/Gemfile +1 -0
  77. data/examples/hi_real_time_async_celluloid/hi.rb +7 -3
  78. data/examples/hi_real_time_async_eventmachine/Gemfile +1 -0
  79. data/examples/hi_real_time_async_eventmachine/hi.rb +7 -3
  80. data/examples/hi_web/Gemfile +1 -0
  81. data/examples/hi_web/hi.rb +1 -0
  82. data/examples/new_ticket/Gemfile +1 -0
  83. data/examples/new_ticket/new_ticket.rb +1 -0
  84. data/lib/slack-ruby-client.rb +8 -2
  85. data/lib/slack.rb +1 -0
  86. data/lib/slack/config.rb +1 -0
  87. data/lib/slack/events/config.rb +32 -0
  88. data/lib/slack/events/request.rb +66 -0
  89. data/lib/slack/logger.rb +6 -5
  90. data/lib/slack/messages/formatting.rb +1 -0
  91. data/lib/slack/messages/message.rb +1 -0
  92. data/lib/slack/real_time/api/message.rb +3 -1
  93. data/lib/slack/real_time/api/message_id.rb +1 -0
  94. data/lib/slack/real_time/api/ping.rb +5 -2
  95. data/lib/slack/real_time/api/typing.rb +3 -1
  96. data/lib/slack/real_time/client.rb +97 -28
  97. data/lib/slack/real_time/concurrency.rb +2 -0
  98. data/lib/slack/real_time/concurrency/async.rb +142 -0
  99. data/lib/slack/real_time/concurrency/celluloid.rb +33 -9
  100. data/lib/slack/real_time/concurrency/eventmachine.rb +32 -7
  101. data/lib/slack/real_time/config.rb +7 -2
  102. data/lib/slack/real_time/models.rb +1 -0
  103. data/lib/slack/real_time/models/base.rb +1 -0
  104. data/lib/slack/real_time/models/bot.rb +1 -0
  105. data/lib/slack/real_time/models/channel.rb +1 -0
  106. data/lib/slack/real_time/models/group.rb +1 -0
  107. data/lib/slack/real_time/models/im.rb +1 -0
  108. data/lib/slack/real_time/models/team.rb +1 -0
  109. data/lib/slack/real_time/models/user.rb +1 -0
  110. data/lib/slack/real_time/socket.rb +42 -13
  111. data/lib/slack/real_time/stores.rb +1 -0
  112. data/lib/slack/real_time/stores/base.rb +1 -0
  113. data/lib/slack/real_time/stores/starter.rb +11 -0
  114. data/lib/slack/real_time/stores/store.rb +28 -25
  115. data/lib/slack/version.rb +2 -1
  116. data/lib/slack/web/api/endpoints.rb +41 -0
  117. data/lib/slack/web/api/endpoints/admin_apps.rb +42 -0
  118. data/lib/slack/web/api/endpoints/admin_apps_approved.rb +35 -0
  119. data/lib/slack/web/api/endpoints/admin_apps_requests.rb +33 -0
  120. data/lib/slack/web/api/endpoints/admin_apps_restricted.rb +35 -0
  121. data/lib/slack/web/api/endpoints/admin_conversations.rb +30 -0
  122. data/lib/slack/web/api/endpoints/admin_emoji.rb +88 -0
  123. data/lib/slack/web/api/endpoints/admin_inviteRequests.rb +61 -0
  124. data/lib/slack/web/api/endpoints/admin_inviteRequests_approved.rb +33 -0
  125. data/lib/slack/web/api/endpoints/admin_inviteRequests_denied.rb +33 -0
  126. data/lib/slack/web/api/endpoints/admin_teams.rb +50 -0
  127. data/lib/slack/web/api/endpoints/admin_teams_admins.rb +34 -0
  128. data/lib/slack/web/api/endpoints/admin_teams_owners.rb +34 -0
  129. data/lib/slack/web/api/endpoints/admin_teams_settings.rb +99 -0
  130. data/lib/slack/web/api/endpoints/admin_users.rb +163 -0
  131. data/lib/slack/web/api/endpoints/admin_users_session.rb +28 -0
  132. data/lib/slack/web/api/endpoints/api.rb +1 -0
  133. data/lib/slack/web/api/endpoints/apps.rb +27 -0
  134. data/lib/slack/web/api/endpoints/apps_permissions.rb +1 -0
  135. data/lib/slack/web/api/endpoints/apps_permissions_resources.rb +1 -0
  136. data/lib/slack/web/api/endpoints/apps_permissions_scopes.rb +1 -0
  137. data/lib/slack/web/api/endpoints/apps_permissions_users.rb +1 -0
  138. data/lib/slack/web/api/endpoints/auth.rb +1 -0
  139. data/lib/slack/web/api/endpoints/bots.rb +1 -0
  140. data/lib/slack/web/api/endpoints/channels.rb +3 -0
  141. data/lib/slack/web/api/endpoints/chat.rb +99 -12
  142. data/lib/slack/web/api/endpoints/chat_scheduledMessages.rb +38 -0
  143. data/lib/slack/web/api/endpoints/conversations.rb +4 -1
  144. data/lib/slack/web/api/endpoints/dialog.rb +1 -0
  145. data/lib/slack/web/api/endpoints/dnd.rb +3 -1
  146. data/lib/slack/web/api/endpoints/emoji.rb +1 -0
  147. data/lib/slack/web/api/endpoints/files.rb +4 -13
  148. data/lib/slack/web/api/endpoints/files_comments.rb +1 -33
  149. data/lib/slack/web/api/endpoints/files_remote.rb +127 -0
  150. data/lib/slack/web/api/endpoints/groups.rb +1 -0
  151. data/lib/slack/web/api/endpoints/im.rb +1 -0
  152. data/lib/slack/web/api/endpoints/migration.rb +1 -0
  153. data/lib/slack/web/api/endpoints/mpim.rb +1 -0
  154. data/lib/slack/web/api/endpoints/oauth.rb +2 -1
  155. data/lib/slack/web/api/endpoints/oauth_v2.rb +30 -0
  156. data/lib/slack/web/api/endpoints/pins.rb +2 -4
  157. data/lib/slack/web/api/endpoints/reactions.rb +5 -6
  158. data/lib/slack/web/api/endpoints/reminders.rb +1 -0
  159. data/lib/slack/web/api/endpoints/rtm.rb +1 -0
  160. data/lib/slack/web/api/endpoints/search.rb +1 -0
  161. data/lib/slack/web/api/endpoints/stars.rb +1 -0
  162. data/lib/slack/web/api/endpoints/team.rb +3 -0
  163. data/lib/slack/web/api/endpoints/team_profile.rb +1 -0
  164. data/lib/slack/web/api/endpoints/usergroups.rb +1 -0
  165. data/lib/slack/web/api/endpoints/usergroups_users.rb +1 -0
  166. data/lib/slack/web/api/endpoints/users.rb +1 -2
  167. data/lib/slack/web/api/endpoints/users_admin.rb +1 -0
  168. data/lib/slack/web/api/endpoints/users_prefs.rb +1 -0
  169. data/lib/slack/web/api/endpoints/users_profile.rb +1 -0
  170. data/lib/slack/web/api/endpoints/views.rb +97 -0
  171. data/lib/slack/web/api/error.rb +1 -0
  172. data/lib/slack/web/api/errors.rb +566 -0
  173. data/lib/slack/web/api/errors/slack_error.rb +14 -1
  174. data/lib/slack/web/api/errors/too_many_requests_error.rb +1 -0
  175. data/lib/slack/web/api/mixins.rb +1 -0
  176. data/lib/slack/web/api/mixins/channels.id.rb +1 -0
  177. data/lib/slack/web/api/mixins/groups.id.rb +1 -0
  178. data/lib/slack/web/api/mixins/ids.id.rb +4 -1
  179. data/lib/slack/web/api/mixins/users.id.rb +1 -0
  180. data/lib/slack/web/api/mixins/users.search.rb +1 -0
  181. data/lib/slack/web/api/patches/chat.5.postEphemeral-text-or-attachments.patch +5 -3
  182. data/lib/slack/web/api/patches/chat.6.block-kit-support.patch +69 -0
  183. data/lib/slack/web/api/patches/views.1.view-json.patch +40 -0
  184. data/lib/slack/web/api/patches/views.1.views-published.patch +16 -0
  185. data/lib/slack/web/api/templates/command.erb +1 -0
  186. data/lib/slack/web/api/templates/commands.erb +1 -0
  187. data/lib/slack/web/api/templates/endpoints.erb +1 -0
  188. data/lib/slack/web/api/templates/errors.erb +20 -0
  189. data/lib/slack/web/api/templates/method.erb +1 -0
  190. data/lib/slack/web/api/templates/method_spec.erb +1 -0
  191. data/lib/slack/web/client.rb +2 -1
  192. data/lib/slack/web/config.rb +1 -0
  193. data/lib/slack/web/faraday/connection.rb +1 -0
  194. data/lib/slack/web/faraday/request.rb +1 -0
  195. data/lib/slack/web/faraday/response/raise_error.rb +10 -6
  196. data/lib/slack/web/pagination/cursor.rb +4 -0
  197. data/lib/slack_ruby_client.rb +1 -0
  198. data/lib/tasks/git.rake +1 -0
  199. data/lib/tasks/real_time.rake +15 -5
  200. data/lib/tasks/update.rake +1 -0
  201. data/lib/tasks/web.rake +28 -7
  202. data/screenshots/create-app.png +0 -0
  203. data/slack-ruby-client.gemspec +6 -2
  204. data/spec/fixtures/slack/web/views_open_error.yml +76 -0
  205. data/spec/integration/integration_spec.rb +116 -48
  206. data/spec/slack/config_spec.rb +2 -0
  207. data/spec/slack/events/config_spec.rb +33 -0
  208. data/spec/slack/events/request_spec.rb +179 -0
  209. data/spec/slack/messages/formatting_spec.rb +25 -13
  210. data/spec/slack/real_time/api/message_spec.rb +6 -1
  211. data/spec/slack/real_time/api/ping_spec.rb +2 -0
  212. data/spec/slack/real_time/api/typing_spec.rb +5 -1
  213. data/spec/slack/real_time/client_spec.rb +212 -31
  214. data/spec/slack/real_time/concurrency/celluloid_spec.rb +15 -5
  215. data/spec/slack/real_time/concurrency/eventmachine_spec.rb +11 -1
  216. data/spec/slack/real_time/concurrency/it_behaves_like_a_realtime_socket.rb +2 -0
  217. data/spec/slack/real_time/event_handlers/bot_spec.rb +2 -1
  218. data/spec/slack/real_time/event_handlers/channel_spec.rb +9 -6
  219. data/spec/slack/real_time/event_handlers/event_handlers_spec.rb +2 -1
  220. data/spec/slack/real_time/event_handlers/group_spec.rb +5 -4
  221. data/spec/slack/real_time/event_handlers/im_spec.rb +4 -3
  222. data/spec/slack/real_time/event_handlers/team_spec.rb +3 -1
  223. data/spec/slack/real_time/event_handlers/user_spec.rb +1 -0
  224. data/spec/slack/real_time/rtm_connect_spec.rb +1 -0
  225. data/spec/slack/real_time/rtm_start_spec.rb +1 -0
  226. data/spec/slack/real_time/store_spec.rb +2 -1
  227. data/spec/slack/slack_spec.rb +37 -5
  228. data/spec/slack/version_spec.rb +2 -1
  229. data/spec/slack/web/api/endpoints/admin_apps_approved_spec.rb +8 -0
  230. data/spec/slack/web/api/endpoints/admin_apps_requests_spec.rb +8 -0
  231. data/spec/slack/web/api/endpoints/admin_apps_restricted_spec.rb +8 -0
  232. data/spec/slack/web/api/endpoints/admin_apps_spec.rb +8 -0
  233. data/spec/slack/web/api/endpoints/admin_conversations_spec.rb +13 -0
  234. data/spec/slack/web/api/endpoints/admin_emoji_spec.rb +37 -0
  235. data/spec/slack/web/api/endpoints/admin_inviteRequests_approved_spec.rb +8 -0
  236. data/spec/slack/web/api/endpoints/admin_inviteRequests_denied_spec.rb +8 -0
  237. data/spec/slack/web/api/endpoints/admin_inviteRequests_spec.rb +18 -0
  238. data/spec/slack/web/api/endpoints/admin_teams_admins_spec.rb +13 -0
  239. data/spec/slack/web/api/endpoints/admin_teams_owners_spec.rb +13 -0
  240. data/spec/slack/web/api/endpoints/admin_teams_settings_spec.rb +53 -0
  241. data/spec/slack/web/api/endpoints/admin_teams_spec.rb +16 -0
  242. data/spec/slack/web/api/endpoints/admin_users_session_spec.rb +13 -0
  243. data/spec/slack/web/api/endpoints/admin_users_spec.rb +75 -0
  244. data/spec/slack/web/api/endpoints/api_spec.rb +1 -0
  245. data/spec/slack/web/api/endpoints/apps_permissions_resources_spec.rb +1 -0
  246. data/spec/slack/web/api/endpoints/apps_permissions_scopes_spec.rb +1 -0
  247. data/spec/slack/web/api/endpoints/apps_permissions_spec.rb +3 -2
  248. data/spec/slack/web/api/endpoints/apps_permissions_users_spec.rb +4 -3
  249. data/spec/slack/web/api/endpoints/apps_spec.rb +16 -0
  250. data/spec/slack/web/api/endpoints/bots_spec.rb +1 -0
  251. data/spec/slack/web/api/endpoints/chat_scheduledMessages_spec.rb +8 -0
  252. data/spec/slack/web/api/endpoints/conversations_spec.rb +2 -1
  253. data/spec/slack/web/api/endpoints/custom_specs/auth_spec.rb +5 -1
  254. data/spec/slack/web/api/endpoints/custom_specs/channels_spec.rb +2 -0
  255. data/spec/slack/web/api/endpoints/custom_specs/chat_spec.rb +112 -36
  256. data/spec/slack/web/api/endpoints/custom_specs/dialog_spec.rb +12 -4
  257. data/spec/slack/web/api/endpoints/custom_specs/groups_spec.rb +2 -0
  258. data/spec/slack/web/api/endpoints/custom_specs/users_spec.rb +6 -1
  259. data/spec/slack/web/api/endpoints/custom_specs/views_spec.rb +95 -0
  260. data/spec/slack/web/api/endpoints/dnd_spec.rb +6 -0
  261. data/spec/slack/web/api/endpoints/emoji_spec.rb +1 -0
  262. data/spec/slack/web/api/endpoints/files_comments_spec.rb +1 -19
  263. data/spec/slack/web/api/endpoints/files_remote_spec.rb +24 -0
  264. data/spec/slack/web/api/endpoints/files_spec.rb +1 -0
  265. data/spec/slack/web/api/endpoints/im_spec.rb +1 -0
  266. data/spec/slack/web/api/endpoints/migration_spec.rb +1 -0
  267. data/spec/slack/web/api/endpoints/mpim_spec.rb +1 -0
  268. data/spec/slack/web/api/endpoints/oauth_spec.rb +1 -0
  269. data/spec/slack/web/api/endpoints/oauth_v2_spec.rb +13 -0
  270. data/spec/slack/web/api/endpoints/pins_spec.rb +5 -1
  271. data/spec/slack/web/api/endpoints/reactions_spec.rb +8 -1
  272. data/spec/slack/web/api/endpoints/reminders_spec.rb +1 -0
  273. data/spec/slack/web/api/endpoints/rtm_spec.rb +1 -0
  274. data/spec/slack/web/api/endpoints/search_spec.rb +1 -0
  275. data/spec/slack/web/api/endpoints/stars_spec.rb +1 -0
  276. data/spec/slack/web/api/endpoints/team_profile_spec.rb +1 -0
  277. data/spec/slack/web/api/endpoints/team_spec.rb +1 -0
  278. data/spec/slack/web/api/endpoints/usergroups_spec.rb +1 -0
  279. data/spec/slack/web/api/endpoints/usergroups_users_spec.rb +1 -0
  280. data/spec/slack/web/api/endpoints/users_admin_spec.rb +1 -0
  281. data/spec/slack/web/api/endpoints/users_prefs_spec.rb +1 -0
  282. data/spec/slack/web/api/endpoints/users_profile_spec.rb +1 -0
  283. data/spec/slack/web/api/endpoints/views_spec.rb +29 -0
  284. data/spec/slack/web/api/error_spec.rb +4 -2
  285. data/spec/slack/web/api/errors/service_unavailable_spec.rb +6 -3
  286. data/spec/slack/web/api/errors/slack_error_spec.rb +26 -2
  287. data/spec/slack/web/api/mixins/channels_spec.rb +17 -7
  288. data/spec/slack/web/api/mixins/groups_spec.rb +17 -7
  289. data/spec/slack/web/api/mixins/users_spec.rb +17 -8
  290. data/spec/slack/web/api/pagination/cursor_spec.rb +40 -10
  291. data/spec/slack/web/client_spec.rb +45 -18
  292. data/spec/slack/web/faraday/response/raise_error_spec.rb +41 -7
  293. data/spec/spec_helper.rb +8 -1
  294. data/spec/support/queue_with_timeout.rb +5 -4
  295. data/spec/support/real_time/concurrency/mock.rb +1 -0
  296. data/spec/support/real_time/connected_client.rb +9 -3
  297. data/spec/support/real_time/event.rb +1 -0
  298. data/spec/support/token.rb +1 -0
  299. data/spec/support/vcr.rb +1 -0
  300. metadata +149 -9
  301. data/screenshots/register-bot.png +0 -0
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'slack-ruby-client'
2
3
 
3
4
  Slack.configure do |config|
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'slack/version'
2
3
  require_relative 'slack/logger'
3
4
  require_relative 'slack/config'
@@ -14,18 +15,19 @@ require 'json'
14
15
  require 'logger'
15
16
  begin
16
17
  require 'picky'
17
- rescue LoadError
18
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
18
19
  # ignore, only used in users_search
19
20
  end
20
21
  begin
21
22
  require 'openssl'
22
- rescue LoadError
23
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
23
24
  # Used in slack/web/config
24
25
  end
25
26
  require_relative 'slack/web/config'
26
27
  require_relative 'slack/web/api/errors/slack_error'
27
28
  require_relative 'slack/web/api/errors/too_many_requests_error'
28
29
  require_relative 'slack/web/api/error'
30
+ require_relative 'slack/web/api/errors'
29
31
  require_relative 'slack/web/faraday/response/raise_error'
30
32
  require_relative 'slack/web/faraday/connection'
31
33
  require_relative 'slack/web/faraday/request'
@@ -47,3 +49,7 @@ require_relative 'slack/real_time/models'
47
49
  require_relative 'slack/real_time/stores'
48
50
  require_relative 'slack/real_time/config'
49
51
  require_relative 'slack/real_time/client'
52
+
53
+ # Events API
54
+ require_relative 'slack/events/config'
55
+ require_relative 'slack/events/request'
@@ -1 +1,2 @@
1
+ # frozen_string_literal: true
1
2
  require 'slack-ruby-client'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module Config
3
4
  extend self
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module Slack
3
+ module Events
4
+ module Config
5
+ extend self
6
+
7
+ ATTRIBUTES = %i[
8
+ signing_secret
9
+ signature_expires_in
10
+ ].freeze
11
+
12
+ attr_accessor(*Config::ATTRIBUTES)
13
+
14
+ def reset
15
+ self.signing_secret = ENV['SLACK_SIGNING_SECRET']
16
+ self.signature_expires_in = 5 * 60
17
+ end
18
+ end
19
+
20
+ class << self
21
+ def configure
22
+ block_given? ? yield(Config) : Config
23
+ end
24
+
25
+ def config
26
+ Config
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ Slack::Events::Config.reset
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+ module Slack
3
+ module Events
4
+ class Request
5
+ class MissingSigningSecret < StandardError; end
6
+ class TimestampExpired < StandardError; end
7
+ class InvalidSignature < StandardError; end
8
+
9
+ attr_reader :http_request,
10
+ :signing_secret,
11
+ :signature_expires_in
12
+
13
+ def initialize(http_request, options = {})
14
+ @http_request = http_request
15
+ @signing_secret = options[:signing_secret] || Slack::Events.config.signing_secret
16
+ @signature_expires_in =
17
+ options[:signature_expires_in] || Slack::Events.config.signature_expires_in
18
+ end
19
+
20
+ # Request timestamp.
21
+ def timestamp
22
+ @timestamp ||= http_request.headers['X-Slack-Request-Timestamp']
23
+ end
24
+
25
+ # The signature is created by combining the signing secret with the body of the request
26
+ # Slack is sending using a standard HMAC-SHA256 keyed hash.
27
+ def signature
28
+ @signature ||= http_request.headers['X-Slack-Signature']
29
+ end
30
+
31
+ # Signature version.
32
+ def version
33
+ 'v0'
34
+ end
35
+
36
+ # Request body.
37
+ def body
38
+ @body ||= http_request.body.read
39
+ end
40
+
41
+ # Returns true if the signature coming from Slack has expired.
42
+ def expired?
43
+ timestamp.nil? || (Time.now.to_i - timestamp.to_i).abs > signature_expires_in
44
+ end
45
+
46
+ # Returns true if the signature coming from Slack is valid.
47
+ def valid?
48
+ raise MissingSigningSecret unless signing_secret
49
+
50
+ digest = OpenSSL::Digest::SHA256.new
51
+ signature_basestring = [version, timestamp, body].join(':')
52
+ hex_hash = OpenSSL::HMAC.hexdigest(digest, signing_secret, signature_basestring)
53
+ computed_signature = [version, hex_hash].join('=')
54
+ computed_signature == signature
55
+ end
56
+
57
+ # Validates the request signature and its expiration.
58
+ def verify!
59
+ raise TimestampExpired if expired?
60
+ raise InvalidSignature unless valid?
61
+
62
+ true
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  require 'logger'
2
3
 
3
4
  module Slack
4
5
  class Logger < ::Logger
5
6
  def self.default
6
- @logger ||= begin
7
- logger = new STDOUT
8
- logger.level = Logger::WARN
9
- logger
10
- end
7
+ return @default if @default
8
+
9
+ logger = new STDOUT
10
+ logger.level = Logger::WARN
11
+ @default = logger
11
12
  end
12
13
  end
13
14
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module Messages
3
4
  module Formatting
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module Messages
3
4
  class Message < Hashie::Mash
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Api
@@ -6,7 +7,8 @@ module Slack
6
7
  # Sends a message to a channel.
7
8
  #
8
9
  # @option options [channel] :channel
9
- # Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name.
10
+ # Channel to send message to. Can be a public channel, private group or IM channel.
11
+ # Can be an encoded ID, or a name.
10
12
  # @option options [Object] :text
11
13
  # Text of the message to send. See below for an explanation of formatting.
12
14
  def message(options = {})
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Api
@@ -1,10 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Api
4
5
  module Ping
5
6
  #
6
- # Clients should try to quickly detect disconnections, even in idle periods, so that users can easily tell the
7
- # difference between being disconnected and everyone being quiet. Not all web browsers support the WebSocket
7
+ # Clients should try to quickly detect disconnections, even in idle periods, so that users
8
+ # can easily tell the
9
+ # difference between being disconnected and everyone being quiet. Not all web browsers
10
+ # support the WebSocket
8
11
  # ping spec, so the RTM protocol also supports ping/pong messages.
9
12
  #
10
13
  def ping(options = {})
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  module Api
@@ -6,7 +7,8 @@ module Slack
6
7
  # Send a typing indicator to indicate that the user is currently writing a message.
7
8
  #
8
9
  # @option options [channel] :channel
9
- # Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name.
10
+ # Channel to send message to. Can be a public channel, private group or IM channel.
11
+ # Can be an encoded ID, or a name.
10
12
  def typing(options = {})
11
13
  throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil?
12
14
  send_json({ type: 'typing', id: next_id }.merge(options))
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Slack
2
3
  module RealTime
3
4
  class Client
@@ -19,8 +20,8 @@ module Slack
19
20
  attr_accessor :store
20
21
  attr_accessor :url
21
22
  attr_accessor(*Config::ATTRIBUTES)
23
+ attr_accessor :logger
22
24
 
23
- protected :logger, :logger=
24
25
  protected :store_class, :store_class=
25
26
 
26
27
  def initialize(options = {})
@@ -35,7 +36,7 @@ module Slack
35
36
 
36
37
  %i[users self channels team teams groups ims bots].each do |store_method|
37
38
  define_method store_method do
38
- store.send(store_method) if store
39
+ store&.send(store_method)
39
40
  end
40
41
  end
41
42
 
@@ -47,7 +48,7 @@ module Slack
47
48
  # Start RealTime client and block until it disconnects.
48
49
  def start!(&block)
49
50
  @callback = block if block_given?
50
- @socket = build_socket
51
+ build_socket
51
52
  @socket.start_sync(self)
52
53
  end
53
54
 
@@ -55,17 +56,18 @@ module Slack
55
56
  # The RealTime::Client will run in the background.
56
57
  def start_async(&block)
57
58
  @callback = block if block_given?
58
- @socket = build_socket
59
+ build_socket
59
60
  @socket.start_async(self)
60
61
  end
61
62
 
62
63
  def stop!
63
64
  raise ClientNotStartedError unless started?
64
- @socket.disconnect! if @socket
65
+
66
+ @socket&.disconnect!
65
67
  end
66
68
 
67
69
  def started?
68
- @socket && @socket.connected?
70
+ @socket&.connected?
69
71
  end
70
72
 
71
73
  class << self
@@ -80,38 +82,105 @@ module Slack
80
82
 
81
83
  def run_loop
82
84
  @socket.connect! do |driver|
83
- @callback.call(driver) if @callback
84
-
85
85
  driver.on :open do |event|
86
- logger.debug("#{self.class}##{__method__}") { event.class.name }
87
- open(event)
86
+ logger.debug("#{self}##{__method__}") { event.class.name }
87
+ open_event(event)
88
88
  callback(event, :open)
89
89
  end
90
90
 
91
91
  driver.on :message do |event|
92
- logger.debug("#{self.class}##{__method__}") { "#{event.class}, #{event.data}" }
92
+ logger.debug("#{self}##{__method__}") { "#{event.class}, #{event.data}" }
93
93
  dispatch(event)
94
94
  end
95
95
 
96
96
  driver.on :close do |event|
97
- logger.debug("#{self.class}##{__method__}") { event.class.name }
97
+ logger.debug("#{self}##{__method__}") { event.class.name }
98
98
  callback(event, :close)
99
99
  close(event)
100
100
  callback(event, :closed)
101
101
  end
102
+
103
+ # This must be called last to ensure any events are registered before invoking user code.
104
+ @callback&.call(driver)
105
+ end
106
+ end
107
+
108
+ # Ensure the server is running, and ping the remote server if no other messages were sent.
109
+ def keep_alive?
110
+ # We can't ping the remote server if we aren't connected.
111
+ return false if @socket.nil? || !@socket.connected?
112
+
113
+ time_since_last_message = @socket.time_since_last_message
114
+
115
+ # If the server responded within the specified time, we are okay:
116
+ return true if time_since_last_message < websocket_ping
117
+
118
+ # If the server has not responded for a while:
119
+ return false if time_since_last_message > (websocket_ping * 2)
120
+
121
+ # Kick off the next ping message:
122
+ ping
123
+
124
+ true
125
+ end
126
+
127
+ # Check if the remote server is responsive, and if not, restart the connection.
128
+ def run_ping!
129
+ return if keep_alive?
130
+
131
+ logger.warn(to_s) { 'is offline' }
132
+
133
+ restart_async
134
+ rescue Slack::Web::Api::Errors::SlackError => e
135
+ # stop pinging if bot was uninstalled
136
+ case e.message
137
+ when 'account_inactive', 'invalid_auth' then
138
+ logger.warn(to_s) { e.message }
139
+ raise e
140
+ end
141
+ logger.debug("#{self}##{__method__}") { e }
142
+ rescue StandardError => e
143
+ # disregard all ping worker failures, keep pinging
144
+ logger.debug("#{self}##{__method__}") { e }
145
+ end
146
+
147
+ def run_ping?
148
+ !websocket_ping.nil? && websocket_ping.positive?
149
+ end
150
+
151
+ def websocket_ping_timer
152
+ websocket_ping / 2
153
+ end
154
+
155
+ def to_s
156
+ if store&.team
157
+ "id=#{store.team.id}, name=#{store.team.name}, domain=#{store.team.domain}"
158
+ else
159
+ super
102
160
  end
103
161
  end
104
162
 
105
163
  protected
106
164
 
165
+ def restart_async
166
+ logger.debug("#{self}##{__method__}")
167
+ @socket.close
168
+ start = web_client.send(rtm_start_method, start_options)
169
+ data = Slack::Messages::Message.new(start)
170
+ @url = data.url
171
+ @store = @store_class.new(data) if @store_class
172
+ @socket.restart_async(self, @url)
173
+ end
174
+
107
175
  # @return [Slack::RealTime::Socket]
108
176
  def build_socket
109
177
  raise ClientAlreadyStartedError if started?
178
+
110
179
  start = web_client.send(rtm_start_method, start_options)
111
180
  data = Slack::Messages::Message.new(start)
112
181
  @url = data.url
113
182
  @store = @store_class.new(data) if @store_class
114
- socket_class.new(@url, socket_options)
183
+ @socket = socket_class.new(@url, socket_options)
115
184
  end
116
185
 
117
186
  def rtm_start_method
@@ -139,17 +208,15 @@ module Slack
139
208
 
140
209
  def send_json(data)
141
210
  raise ClientNotStartedError unless started?
142
- logger.debug("#{self.class}##{__method__}") { data }
211
+
212
+ logger.debug("#{self}##{__method__}") { data }
143
213
  @socket.send_data(data.to_json)
144
214
  end
145
215
 
146
- def open(_event); end
216
+ def open_event(_event); end
147
217
 
148
218
  def close(_event)
149
- socket = @socket
150
- @socket = nil
151
-
152
- [socket, socket_class].each do |s|
219
+ [@socket, socket_class].each do |s|
153
220
  s.close if s.respond_to?(:close)
154
221
  end
155
222
  end
@@ -157,50 +224,52 @@ module Slack
157
224
  def callback(event, type)
158
225
  callbacks = self.callbacks[type.to_s]
159
226
  return false unless callbacks
227
+
160
228
  callbacks.each do |c|
161
229
  c.call(event)
162
230
  end
163
231
  true
164
232
  rescue StandardError => e
165
- logger.error e
233
+ logger.error("#{self}##{__method__}") { e }
166
234
  false
167
235
  end
168
236
 
169
237
  def dispatch(event)
170
238
  return false unless event.data
239
+
171
240
  data = Slack::Messages::Message.new(JSON.parse(event.data))
172
241
  type = data.type
173
242
  return false unless type
243
+
174
244
  type = type.to_s
175
- logger.debug("#{self.class}##{__method__}") { data.to_s }
245
+ logger.debug("#{self}##{__method__}") { data.to_s }
176
246
  run_handlers(type, data) if @store
177
247
  run_callbacks(type, data)
178
248
  rescue StandardError => e
179
- logger.error e
249
+ logger.error("#{self}##{__method__}") { e }
180
250
  false
181
251
  end
182
252
 
183
253
  def run_handlers(type, data)
184
254
  handlers = store.class.events[type.to_s]
185
- if handlers
186
- handlers.each do |handler|
187
- store.instance_exec(data, &handler)
188
- end
255
+ handlers&.each do |handler|
256
+ store.instance_exec(data, &handler)
189
257
  end
190
258
  rescue StandardError => e
191
- logger.error e
259
+ logger.error("#{self}##{__method__}") { e }
192
260
  false
193
261
  end
194
262
 
195
263
  def run_callbacks(type, data)
196
264
  callbacks = self.callbacks[type]
197
265
  return false unless callbacks
266
+
198
267
  callbacks.each do |c|
199
268
  c.call(data)
200
269
  end
201
270
  true
202
271
  rescue StandardError => e
203
- logger.error e
272
+ logger.error("#{self}##{__method__}") { e }
204
273
  false
205
274
  end
206
275
  end