slack_msgr 0.0.1 → 0.0.7

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
- SHA1:
3
- metadata.gz: fd274c89233b9e5903e49f7e4243a859f2e78c74
4
- data.tar.gz: 7ba179fb4226cf6fafb36f6735c80b10daf28b3c
2
+ SHA256:
3
+ metadata.gz: 4e8ddbcbfbd549eb2c4ab898505896bf2d99ad950b1dda24167c4c7b0af2274f
4
+ data.tar.gz: 2d9f90f36aa0cc306ddf6b968b89cdf2280a41ef72b222ac00356c3fe685562b
5
5
  SHA512:
6
- metadata.gz: 1998160597b692ff67d57b2c6c794c6f3b807037c0da3186d6a5c6b4b46eb7caf1c70220dd8d08938b537fbae9078a06f305093a5efb99733ec8ce284fdb86ff
7
- data.tar.gz: 227e030f4de7db7f7c0ed5134217e6594d1efa5f2b71011dae41010bc2898754cbe76e952426d9b27cf107c5f2566df82707e5796a430fe808927000e4bc9f1b
6
+ metadata.gz: e8ee2351b8481befbd89f910b0f48855d5dfde409ac4611f7121de5311f2e7021b2553813f280539bdec5c17a208631f0e50c667766e443168ebb4475d72882b
7
+ data.tar.gz: 83810c251a1b51364de4d0f51ac216e3ceba00ee5f4a47a1a4d33dc35d88facc61826243212d11f9959acf12e099a20f686c1af6354aa6b43c12c9280459b570
@@ -58,10 +58,10 @@ AllCops:
58
58
  - bin/**
59
59
 
60
60
  Metrics/LineLength:
61
- Description: 'Limit lines to 100 characters.'
62
- StyleGuide: '#100-character-limits'
61
+ Description: 'Limit lines to 120 characters.'
62
+ StyleGuide: '#120-character-limits'
63
63
  Enabled: true
64
- Max: 100
64
+ Max: 120
65
65
  # To make it possible to copy or click on URIs in the code, we allow lines
66
66
  # containing a URI to be longer than Max.
67
67
  AllowHeredoc: true
@@ -0,0 +1 @@
1
+ ruby 2.6.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slack_msgr (0.0.1)
4
+ slack_msgr (0.0.7)
5
5
  faraday (~> 0.15.4)
6
6
 
7
7
  GEM
@@ -26,7 +26,7 @@ GEM
26
26
  multipart-post (>= 1.2, < 3)
27
27
  ice_nine (0.11.2)
28
28
  jaro_winkler (1.5.2)
29
- json (2.2.0)
29
+ json (2.3.1)
30
30
  kwalify (0.7.2)
31
31
  method_source (0.9.2)
32
32
  multipart-post (2.1.1)
@@ -38,7 +38,7 @@ GEM
38
38
  method_source (~> 0.9.0)
39
39
  psych (3.1.0)
40
40
  rainbow (3.0.0)
41
- rake (10.5.0)
41
+ rake (13.0.1)
42
42
  reek (5.4.0)
43
43
  codeclimate-engine-rb (~> 0.4.0)
44
44
  kwalify (~> 0.7.0)
@@ -85,7 +85,7 @@ PLATFORMS
85
85
  DEPENDENCIES
86
86
  bundler (~> 2.0)
87
87
  pry
88
- rake (~> 10.0)
88
+ rake (~> 13.0)
89
89
  reek (~> 5.4.0)
90
90
  rspec (~> 3.0)
91
91
  rubocop (~> 0.71.0)
data/README.md CHANGED
@@ -33,14 +33,30 @@ If you are using this gem with a Rails project, create an initializer file.
33
33
  # ./config/initializers/slack_msgr.rb
34
34
 
35
35
  SlackMsgr.configure do |config|
36
- config.verification_token = '1a2b3c4d5e'
37
- config.client_secret = 'a1b2c3d4e5'
38
- config.signing_secret = 'aa11bb22cc3'
39
- config.oauth_access_token = 'xoxp-1234567-xxxxxxxxx'
40
- config.bot_user_oauth_access_token = 'xoxb-1234567-xxxxxxxxx'
36
+ config.verification_token = '1a2b3c4d5e'
37
+ config.client_secret = 'a1b2c3d4e5'
38
+ config.signing_secret = 'aa11bb22cc3'
39
+ config.access_tokens = {
40
+ bot: 'xoxp-1234567-xxxxxxxxx',
41
+ me: 'xoxb-1234567-xxxxxxxxx'
42
+ }
41
43
  end
42
44
  ```
43
45
 
46
+ _NOTE_: All access tokens are configured as a hash. The name of the keys are arbitrary, and there is no limit to keys that can be configured.
47
+
48
+ Multiple oauth tokens can be used during a single session. Oauth tokens are declared in the method execution. For example, considering the configuration above, to use the token attached to the key `:me` simply pass the parameter `use_token: :me`.
49
+
50
+ ```ruby
51
+ SlackMsgr.chat(:post_message,
52
+ use_token: :me,
53
+ channel: 'announcements',
54
+ text: 'Hello world'
55
+ )
56
+ ```
57
+
58
+ SlackMsgr will try to use a default token if a method is called without declaring `use_token:`. SlackMsgr takes the first token in the `access_tokens` hash as a default.
59
+
44
60
  If you are using this gem outside of a Rails project, follow the configuration pattern above, but be sure to run this code before using any functionality of the gem.
45
61
 
46
62
  ## Usage
@@ -59,6 +75,7 @@ SlackMsgr.chat(:post_message, channel: 'announcements', text: 'Hello world')
59
75
  # Sends the text 'Hello world' to the announcements channel
60
76
 
61
77
  SlackMsgr.chat(:post_message, {
78
+ use_token: :bot,
62
79
  channel: "C1H9RESGL",
63
80
  text: "Here's a message for you",
64
81
  as_user: false,
@@ -69,7 +86,7 @@ SlackMsgr.chat(:post_message, {
69
86
  fallback: "This is an attachment's fallback"
70
87
  }]
71
88
  })
72
- # Sends a message with an attachment as a user with the username 'testing'
89
+ # Sends a message with an attachment using the oauth token configured for :bot as a user with the username 'testing'
73
90
  ```
74
91
 
75
92
  ## License
@@ -5,5 +5,5 @@ module SlackMsgr
5
5
 
6
6
  SLACK_URL = 'https://slack.com'
7
7
 
8
- VERSION = '0.0.1'
8
+ VERSION = '0.0.7'
9
9
  end
@@ -2,6 +2,15 @@
2
2
 
3
3
  require 'json'
4
4
  require 'faraday'
5
+ require 'uri'
5
6
  require_relative './constants'
6
7
 
7
- Dir[File.expand_path 'lib/{slack_msgr,utils}/**/*.rb'].each { |f| require f }
8
+ path = __dir__
9
+
10
+ require "#{path}/../slack_msgr/slack_method"
11
+ require "#{path}/../slack_msgr/authenticate"
12
+ require "#{path}/../slack_msgr/chat"
13
+ require "#{path}/../slack_msgr/configuration"
14
+ require "#{path}/../slack_msgr/conversations"
15
+ require "#{path}/../slack_msgr/users"
16
+ require "#{path}/../utils/error_handling"
@@ -11,10 +11,19 @@ module SlackMsgr
11
11
 
12
12
  def configure
13
13
  yield(configuration)
14
+ nil
14
15
  end
15
16
 
16
17
  def chat(method, opts = {})
17
18
  Chat.call(method, opts)
18
19
  end
20
+
21
+ def users(*methods, **opts)
22
+ Users.call(methods, opts)
23
+ end
24
+
25
+ def conversations(method, **opts)
26
+ Conversations.call(method, opts)
27
+ end
19
28
  end
20
29
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlackMsgr
4
+ # Handles various authentication patterns offered by Slack
5
+ class Authenticate
6
+ class << self
7
+ def verification_token?(token)
8
+ token == SlackMsgr.configuration.verification_token
9
+ end
10
+
11
+ def signing_secret?(request)
12
+ signature = request.headers['X-Slack-Signature']
13
+ timestamp = request.headers['X-Slack-Request-Timestamp']
14
+ version = signature.split('=').first
15
+ body = request.body.read
16
+
17
+ # The request timestamp is more than five minutes from local time.
18
+ # It could be a replay attack, so let's ignore it.
19
+ return false if timestamp_over_five_minutes_old?(timestamp)
20
+
21
+ signature == "#{version}=#{compute_hash_sha256(version, timestamp, body)}"
22
+ end
23
+
24
+ private
25
+
26
+ def compute_hash_sha256(version, timestamp, body)
27
+ digest = OpenSSL::Digest::SHA256.new
28
+ OpenSSL::HMAC.hexdigest(digest, SlackMsgr.configuration.signing_secret, "#{version}:#{timestamp}:#{body}")
29
+ end
30
+
31
+ def timestamp_over_five_minutes_old?(timestamp)
32
+ (Time.now - Time.at(timestamp.to_i)) > (60 * 5)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -29,12 +29,7 @@ module SlackMsgr
29
29
  class << self
30
30
  def call(method, opts = {})
31
31
  chat = new(method, opts)
32
-
33
- conn.post do |req|
34
- req.url "/api/#{chat.method}"
35
- req.headers['Content-Type'] = 'application/json; charset=utf-8'
36
- req.body = chat.body
37
- end
32
+ send_post_request_to_slack(chat)
38
33
  end
39
34
  end
40
35
 
@@ -54,7 +49,8 @@ module SlackMsgr
54
49
  private
55
50
 
56
51
  def sanitize_body
57
- ErrorHandling.raise(:req_args_missing, req_args: REQUIRED_ARGUMENTS, method: method) if req_args_missing? # rubocop:disable LineLength
52
+ ErrorHandling.raise(:req_args_missing, req_args: REQUIRED_ARGUMENTS, method: method) if req_args_missing?
53
+
58
54
  opts.keys.each_with_object({}) do |key, body|
59
55
  body[key] ||= opts[key] if PERMITTED_ARGUMENTS.include?(key)
60
56
  body
@@ -6,29 +6,50 @@ module SlackMsgr
6
6
  attr_accessor :verification_token,
7
7
  :client_secret,
8
8
  :signing_secret,
9
- :oauth_access_token,
10
- :bot_user_oauth_access_token
9
+ :legacy_token,
10
+ :access_tokens,
11
+ :set_default_token
11
12
 
12
- def initialize(
13
+ def initialize( # rubocop:disable Metrics/ParameterLists
13
14
  verification_token: nil,
14
15
  client_secret: nil,
15
16
  signing_secret: nil,
16
- oauth_access_token: nil,
17
- bot_user_oauth_access_token: nil
17
+ legacy_token: nil,
18
+ access_tokens: {},
19
+ set_default_token: nil
18
20
  )
19
- @verification_token = verification_token
20
- @client_secret = client_secret
21
- @signing_secret = signing_secret
22
- @oauth_access_token = oauth_access_token
23
- @bot_user_oauth_access_token = bot_user_oauth_access_token
21
+ @verification_token = verification_token
22
+ @client_secret = client_secret
23
+ @signing_secret = signing_secret
24
+ @legacy_token = legacy_token
25
+ @access_tokens = access_tokens
26
+ @set_default_token = set_default_token
24
27
  end
25
28
 
26
29
  def clear!
27
- @verification_token = nil
28
- @client_secret = nil
29
- @signing_secret = nil
30
- @oauth_access_token = nil
31
- @bot_user_oauth_access_token = nil
30
+ @verification_token = nil
31
+ @client_secret = nil
32
+ @signing_secret = nil
33
+ @legacy_token = nil
34
+ @access_tokens = {}
35
+ @set_default_token = nil
36
+ @default_token = nil
37
+ end
38
+
39
+ def default_token
40
+ @default_token ||= initialize_default_token
41
+ end
42
+
43
+ def initialize_default_token
44
+ return unless access_tokens&.first
45
+
46
+ access_tokens[set_default_token] || access_tokens.first[1]
47
+ end
48
+
49
+ def oauth_access_token(given_token)
50
+ token = access_tokens[given_token] || default_token
51
+ ErrorHandling.raise(:configuration_error) unless token
52
+ token
32
53
  end
33
54
  end
34
55
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlackMsgr
4
+ # Handles all conversations functionality and methods corresponding with Slack API
5
+ class Conversations < SlackMethod
6
+ CONVERSATIONS_METHODS = { open: 'open' }.freeze
7
+
8
+ REQUIRED_ARGUMENTS = %i[token users].freeze
9
+
10
+ PERMITTED_ARGUMENTS = %i[token channel return_im users].freeze
11
+
12
+ class << self
13
+ def call(method, opts = {})
14
+ chat = new(method, opts)
15
+ send_post_request_to_slack(chat)
16
+ end
17
+ end
18
+
19
+ attr_reader :method,
20
+ :opts,
21
+ :body
22
+
23
+ def initialize(method, opts)
24
+ conversations_method = CONVERSATIONS_METHODS[method]
25
+ ErrorHandling.raise(:unknown_method, method: method) unless conversations_method
26
+
27
+ @method = "conversations.#{conversations_method}"
28
+ @opts = opts
29
+ @body = sanitize_body
30
+ end
31
+
32
+ private
33
+
34
+ def sanitize_body
35
+ ErrorHandling.raise(:req_args_missing, req_args: REQUIRED_ARGUMENTS, method: method) if req_args_missing?
36
+
37
+ opts.keys.each_with_object({}) do |key, body|
38
+ body[key] ||= opts[key] if PERMITTED_ARGUMENTS.include?(key)
39
+ body
40
+ end.to_json
41
+ end
42
+
43
+ def req_args_missing?
44
+ !(REQUIRED_ARGUMENTS - opts.keys).empty?
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlackMsgr
4
+ # Handles all requests with Slack API
5
+ class SlackMethod
6
+ class << self
7
+ private
8
+
9
+ def conn
10
+ @conn ||= Faraday.new(url: SLACK_URL) do |config|
11
+ config.request :url_encoded # form-encode POST params
12
+ config.adapter Faraday.default_adapter # make requests with Net::HTTP
13
+ end
14
+ end
15
+
16
+ def conceal(token)
17
+ token.split('Bearer ').last[0..-6].gsub(/[a-zA-Z0-9]/, 'X') + token[-5..-1]
18
+ end
19
+
20
+ def add_metadata_to_response(response)
21
+ JSON.parse(response.body, symbolize_names: true)
22
+ .merge!(auth_token: conceal(conn.headers['Authorization']))
23
+ end
24
+
25
+ def send_post_request_to_slack(obj)
26
+ conn.authorization :Bearer, SlackMsgr.configuration.oauth_access_token(obj.opts[:use_token])
27
+ response = conn.post do |req|
28
+ req.url "/api/#{obj.method}"
29
+ req.headers['Content-Type'] = 'application/json; charset=utf-8'
30
+ req.body = obj.body
31
+ end
32
+ add_metadata_to_response(response)
33
+ end
34
+
35
+ def send_legacy_request_to_slack(obj)
36
+ conn.authorization :Bearer, SlackMsgr.configuration.legacy_token
37
+ response = conn.post do |req|
38
+ req.url "/api/#{obj.method}"
39
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
40
+ req.body = URI.encode_www_form(obj.body)
41
+ end
42
+ JSON.parse(response.body, symbolize_names: true)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SlackMsgr
4
+ # Handles all users functionality and methods corresponding with Slack API
5
+ class Users < SlackMethod
6
+ USERS_METHODS = {
7
+ admin: 'admin',
8
+ invite: 'invite'
9
+ }.freeze
10
+
11
+ REQUIRED_ARGUMENTS = %i[email].freeze
12
+
13
+ PERMITTED_ARGUMENTS = %i[
14
+ token
15
+ email
16
+ channels
17
+ real_name
18
+ resend
19
+ restricted
20
+ ultra_restricted
21
+ expiration_ts
22
+ ].freeze
23
+
24
+ class << self
25
+ def call(method, opts = {})
26
+ users = new(method, opts)
27
+ send_legacy_request_to_slack(users)
28
+ end
29
+ end
30
+
31
+ attr_reader :method,
32
+ :opts,
33
+ :body
34
+
35
+ def initialize(methods, opts)
36
+ users_method = methods.map do |method|
37
+ ErrorHandling.raise(:unknown_method, method: method) unless USERS_METHODS[method]
38
+
39
+ USERS_METHODS[method]
40
+ end.join('.')
41
+
42
+ @method = "users.#{users_method}"
43
+ @opts = opts
44
+ @body = sanitize_body
45
+ end
46
+
47
+ private
48
+
49
+ def sanitize_body
50
+ ErrorHandling.raise(:req_args_missing, req_args: REQUIRED_ARGUMENTS, method: method) if req_args_missing?
51
+
52
+ opts.merge!(token).keys.each_with_object({}) do |key, body|
53
+ body[key] ||= opts[key] if PERMITTED_ARGUMENTS.include?(key)
54
+ body
55
+ end
56
+ end
57
+
58
+ def req_args_missing?
59
+ !(REQUIRED_ARGUMENTS - opts.keys).empty?
60
+ end
61
+
62
+ def token
63
+ { token: SlackMsgr.configuration.legacy_token }
64
+ end
65
+ end
66
+ end
@@ -21,8 +21,8 @@ module SlackMsgr
21
21
  def configuration_error(_opts)
22
22
  {
23
23
  exception: ConfigurationError,
24
- message: "Error with configruation: oauth_access_token not found\n" \
25
- 'Be sure to configure all tokens and secrets'
24
+ message: "Error with configruation: access_tokens not found\n" \
25
+ 'At least one oauth token must be configured using access_tokens'
26
26
  }
27
27
  end
28
28
 
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
  spec.add_dependency 'faraday', '~>0.15.4'
34
34
 
35
35
  spec.add_development_dependency 'bundler', '~> 2.0'
36
- spec.add_development_dependency 'rake', '~> 10.0'
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
37
  spec.add_development_dependency 'rspec', '~> 3.0'
38
38
  spec.add_development_dependency 'rubocop', '~> 0.71.0'
39
39
  spec.add_development_dependency 'reek', '~> 5.4.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack_msgr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Workman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-03 00:00:00.000000000 Z
11
+ date: 2020-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '10.0'
47
+ version: '13.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '10.0'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +134,7 @@ files:
134
134
  - ".reek.yml"
135
135
  - ".rspec"
136
136
  - ".rubocop.yml"
137
+ - ".tool-versions"
137
138
  - CODE_OF_CONDUCT.md
138
139
  - Gemfile
139
140
  - Gemfile.lock
@@ -145,9 +146,12 @@ files:
145
146
  - lib/config/constants.rb
146
147
  - lib/config/initializer.rb
147
148
  - lib/slack_msgr.rb
149
+ - lib/slack_msgr/authenticate.rb
148
150
  - lib/slack_msgr/chat.rb
149
151
  - lib/slack_msgr/configuration.rb
150
- - lib/slack_msgr/fetcher.rb
152
+ - lib/slack_msgr/conversations.rb
153
+ - lib/slack_msgr/slack_method.rb
154
+ - lib/slack_msgr/users.rb
151
155
  - lib/utils/error_handling.rb
152
156
  - slack_msgr.gemspec
153
157
  homepage: https://github.com/rdavid1099/slack-msgr
@@ -156,7 +160,7 @@ licenses:
156
160
  metadata:
157
161
  homepage_uri: https://github.com/rdavid1099/slack-msgr
158
162
  source_code_uri: https://github.com/rdavid1099/slack_msgr
159
- post_install_message:
163
+ post_install_message:
160
164
  rdoc_options: []
161
165
  require_paths:
162
166
  - lib
@@ -171,9 +175,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
175
  - !ruby/object:Gem::Version
172
176
  version: '0'
173
177
  requirements: []
174
- rubyforge_project:
175
- rubygems_version: 2.6.14
176
- signing_key:
178
+ rubygems_version: 3.1.4
179
+ signing_key:
177
180
  specification_version: 4
178
181
  summary: A Ruby gem to send and receive messages through Slack
179
182
  test_files: []
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SlackMsgr
4
- # Handles all requests with Slack API
5
- class SlackMethod
6
- class << self
7
- private
8
-
9
- def conn
10
- oauth_access_token = SlackMsgr.configuration.oauth_access_token
11
- ErrorHandling.raise(:configuration_error) unless oauth_access_token
12
-
13
- faraday = Faraday.new(url: SLACK_URL) do |config|
14
- config.request :url_encoded # form-encode POST params
15
- config.adapter Faraday.default_adapter # make requests with Net::HTTP
16
- end
17
- faraday.authorization :Bearer, oauth_access_token
18
- faraday
19
- end
20
- end
21
- end
22
- end