gitlab-mail_room 0.0.4 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab/issue_templates/Default.md +9 -0
  3. data/.gitlab/issue_templates/Release.md +8 -0
  4. data/.gitlab-ci.yml +18 -16
  5. data/.rubocop.yml +5 -0
  6. data/.rubocop_todo.yml +494 -0
  7. data/.ruby-version +1 -1
  8. data/.travis.yml +12 -5
  9. data/CHANGELOG.md +4 -0
  10. data/CONTRIBUTING.md +40 -0
  11. data/README.md +136 -10
  12. data/Rakefile +1 -1
  13. data/lib/mail_room/arbitration/redis.rb +1 -1
  14. data/lib/mail_room/cli.rb +2 -2
  15. data/lib/mail_room/configuration.rb +11 -1
  16. data/lib/mail_room/connection.rb +10 -177
  17. data/lib/mail_room/coordinator.rb +8 -4
  18. data/lib/mail_room/crash_handler.rb +8 -12
  19. data/lib/mail_room/delivery/letter_opener.rb +1 -1
  20. data/lib/mail_room/delivery/postback.rb +36 -4
  21. data/lib/mail_room/delivery/sidekiq.rb +4 -3
  22. data/lib/mail_room/health_check.rb +60 -0
  23. data/lib/mail_room/imap/connection.rb +200 -0
  24. data/lib/mail_room/imap/message.rb +19 -0
  25. data/lib/mail_room/imap.rb +8 -0
  26. data/lib/mail_room/jwt.rb +39 -0
  27. data/lib/mail_room/logger/structured.rb +15 -1
  28. data/lib/mail_room/mailbox.rb +62 -20
  29. data/lib/mail_room/mailbox_watcher.rb +15 -2
  30. data/lib/mail_room/message.rb +16 -0
  31. data/lib/mail_room/microsoft_graph/connection.rb +243 -0
  32. data/lib/mail_room/microsoft_graph.rb +7 -0
  33. data/lib/mail_room/version.rb +2 -2
  34. data/lib/mail_room.rb +2 -0
  35. data/mail_room.gemspec +13 -4
  36. data/spec/fixtures/jwt_secret +1 -0
  37. data/spec/fixtures/test_config.yml +3 -0
  38. data/spec/lib/arbitration/redis_spec.rb +9 -7
  39. data/spec/lib/cli_spec.rb +32 -17
  40. data/spec/lib/configuration_spec.rb +10 -3
  41. data/spec/lib/coordinator_spec.rb +27 -11
  42. data/spec/lib/crash_handler_spec.rb +10 -9
  43. data/spec/lib/delivery/letter_opener_spec.rb +10 -6
  44. data/spec/lib/delivery/logger_spec.rb +8 -10
  45. data/spec/lib/delivery/postback_spec.rb +73 -41
  46. data/spec/lib/delivery/que_spec.rb +5 -8
  47. data/spec/lib/delivery/sidekiq_spec.rb +33 -11
  48. data/spec/lib/health_check_spec.rb +57 -0
  49. data/spec/lib/{connection_spec.rb → imap/connection_spec.rb} +13 -17
  50. data/spec/lib/imap/message_spec.rb +36 -0
  51. data/spec/lib/jwt_spec.rb +80 -0
  52. data/spec/lib/logger/structured_spec.rb +34 -2
  53. data/spec/lib/mailbox_spec.rb +79 -34
  54. data/spec/lib/mailbox_watcher_spec.rb +54 -41
  55. data/spec/lib/message_spec.rb +35 -0
  56. data/spec/lib/microsoft_graph/connection_spec.rb +252 -0
  57. data/spec/spec_helper.rb +14 -4
  58. metadata +130 -21
data/README.md CHANGED
@@ -20,7 +20,14 @@ The fork is useful as we can post quick fixes to our own fork and release fixes
20
20
 
21
21
  ## README
22
22
 
23
- mail_room is a configuration based process that will idle on IMAP connections and execute a delivery method when a new message is received. Examples of delivery methods include:
23
+ mail_room is a configuration based process that will listen for incoming
24
+ e-mail and execute a delivery method when a new message is
25
+ received. mail_room supports the following methods for receiving e-mail:
26
+
27
+ * IMAP
28
+ * [Microsoft Graph API](https://docs.microsoft.com/en-us/graph/api/resources/mail-api-overview?view=graph-rest-1.0)
29
+
30
+ Examples of delivery methods include:
24
31
 
25
32
  * POST to a delivery URL (Postback)
26
33
  * Queue a job to Sidekiq or Que for later processing (Sidekiq or Que)
@@ -55,6 +62,9 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
55
62
 
56
63
  ```yaml
57
64
  ---
65
+ :health_check:
66
+ :address: "127.0.0.1"
67
+ :port: 8080
58
68
  :mailboxes:
59
69
  -
60
70
  :email: "user1@gmail.com"
@@ -114,11 +124,135 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
114
124
  :host: 127.0.0.1
115
125
  :port: 26379
116
126
  :worker: EmailReceiverWorker
127
+ -
128
+ :email: "user7@outlook365.com"
129
+ :password: "password"
130
+ :name: "inbox"
131
+ :inbox_method: microsoft_graph
132
+ :inbox_options:
133
+ :tenant_id: 12345
134
+ :client_id: ABCDE
135
+ :client_secret: YOUR-SECRET-HERE
136
+ :poll_interval: 60
137
+ :azure_ad_endpoint: https://login.microsoftonline.com
138
+ :graph_endpoint: https://graph.microsoft.com
139
+ :delivery_method: sidekiq
140
+ :delivery_options:
141
+ :redis_url: redis://localhost:6379
142
+ :worker: EmailReceiverWorker
143
+ -
144
+ :email: "user8@gmail.com"
145
+ :password: "password"
146
+ :name: "inbox"
147
+ :delivery_method: postback
148
+ :delivery_options:
149
+ :delivery_url: "http://localhost:3000/inbox"
150
+ :jwt_auth_header: "Mailroom-Api-Request"
151
+ :jwt_issuer: "mailroom"
152
+ :jwt_algorithm: "HS256"
153
+ :jwt_secret_path: "/etc/secrets/mailroom/.mailroom_secret"
117
154
  ```
118
155
 
119
156
  **Note:** If using `delete_after_delivery`, you also probably want to use
120
157
  `expunge_deleted` unless you really know what you're doing.
121
158
 
159
+ ## health_check ##
160
+
161
+ Requires `webrick` gem to be installed.
162
+
163
+ This option enables an HTTP server that listens to a bind address
164
+ defined by `address` and `port`. The following endpoints are supported:
165
+
166
+ * `/liveness`: This returns a 200 status code with `OK` as the body if
167
+ the server is running. Otherwise, it returns a 500 status code.
168
+
169
+ This feature is not included in upstream `mail_room` and is specific to GitLab.
170
+
171
+ ## inbox_method
172
+
173
+ By default, IMAP mode is assumed for reading a mailbox.
174
+
175
+ ### IMAP Server Configuration ##
176
+
177
+ You can set per-mailbox configuration for the IMAP server's `host` (default: 'imap.gmail.com'), `port` (default: 993), `ssl` (default: true), and `start_tls` (default: false).
178
+
179
+ If you want to set additional options for IMAP SSL you can pass a YAML hash to match [SSLContext#set_params](http://docs.ruby-lang.org/en/2.2.0/OpenSSL/SSL/SSLContext.html#method-i-set_params). If you set `verify_mode` to `:none` it'll replace with the appropriate constant.
180
+
181
+ If you're seeing the error `Please log in via your web browser: https://support.google.com/mail/accounts/answer/78754 (Failure)`, you need to configure your Gmail account to allow less secure apps to access it: https://support.google.com/accounts/answer/6010255.
182
+
183
+ ### Microsoft Graph configuration
184
+
185
+ To use the Microsoft Graph API instead of IMAP to read e-mail, you will
186
+ need to create an application in the Azure Active Directory. See the
187
+ [Microsoft instructions](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details:
188
+
189
+ 1. Sign in to the [Azure portal](https://portal.azure.com).
190
+ 1. Search for and select `Azure Active Directory`.
191
+ 1. Under `Manage`, select `App registrations` > `New registration`.
192
+ 1. Enter a `Name` for your application, such as `MailRoom`. Users of your app might see this name, and you can change it later.
193
+ 1. If `Supported account types` is listed, select the appropriate option.
194
+ 1. Leave `Redirect URI` blank. This is not needed.
195
+ 1. Select `Register`.
196
+ 1. Under `Manage`, select `Certificates & secrets`.
197
+ 1. Under `Client secrets`, select `New client secret`, and enter a name.
198
+ 1. Under `Expires`, select `Never`, unless you plan on updating the credentials every time it expires.
199
+ 1. Select `Add`. Record the secret value in a safe location for use in a later step.
200
+ 1. Under `Manage`, select `API Permissions` > `Add a permission`. Select `Microsoft Graph`.
201
+ 1. Select `Application permissions`.
202
+ 1. Under the `Mail` node, select `Mail.ReadWrite`, and then select Add permissions.
203
+ 1. If `User.Read` is listed in the permission list, you can delete this.
204
+ 1. Click `Grant admin consent` for these permissions.
205
+
206
+ #### Restrict mailbox access
207
+
208
+ Note that for MailRoom to work as a service account, this application
209
+ must have the `Mail.ReadWrite` to read/write mail in *all*
210
+ mailboxes. However, while this appears to be security risk,
211
+ we can configure an application access policy to limit the
212
+ mailbox access for this account. [Follow these instructions](https://docs.microsoft.com/en-us/graph/auth-limit-mailbox-access)
213
+ to setup PowerShell and configure this policy.
214
+
215
+ #### MailRoom config for Microsoft Graph
216
+
217
+ In the MailRoom configuration, set `inbox_method` to `microsoft_graph`.
218
+ You will also need:
219
+
220
+ * The client and tenant ID from the `Overview` section in the Azure app page
221
+ * The client secret created earlier
222
+
223
+ Fill in `inbox_options` with these values:
224
+
225
+ ```yaml
226
+ :inbox_method: microsoft_graph
227
+ :inbox_options:
228
+ :tenant_id: 12345
229
+ :client_id: ABCDE
230
+ :client_secret: YOUR-SECRET-HERE
231
+ :poll_interval: 60
232
+ ```
233
+
234
+ By default, MailRoom will poll for new messages every 60 seconds. `poll_interval` configures the number of
235
+ seconds to poll. Setting the value to 0 or under will default to 60 seconds.
236
+
237
+ ### Alternative Azure cloud deployments
238
+
239
+ MailRoom will default to using the standard Azure HTTPS endpoints. To
240
+ configure MailRoom with Microsoft Cloud for US Government or other
241
+ [national cloud deployments](https://docs.microsoft.com/en-us/graph/deployments), set
242
+ the `azure_ad_endpoint` and `graph_endpoint` accordingly. For example,
243
+ for Microsoft Cloud for US Government:
244
+
245
+ ```yaml
246
+ :inbox_method: microsoft_graph
247
+ :inbox_options:
248
+ :tenant_id: 12345
249
+ :client_id: ABCDE
250
+ :client_secret: YOUR-SECRET-HERE
251
+ :poll_interval: 60
252
+ :azure_ad_endpoint: https://login.microsoftonline.us
253
+ :graph_endpoint: https://graph.microsoft.us
254
+ ```
255
+
122
256
  ## delivery_method ##
123
257
 
124
258
  ### postback ###
@@ -263,20 +397,12 @@ it's probably because the content-type is set to Faraday's default, which is `H
263
397
  ## idle_timeout ##
264
398
 
265
399
  By default, the IDLE command will wait for 29 minutes (in order to keep the server connection happy).
266
- If you'd prefer not to wait that long, you can pass `imap_timeout` in seconds for your mailbox configuration.
400
+ If you'd prefer not to wait that long, you can pass `idle_timeout` in seconds for your mailbox configuration.
267
401
 
268
402
  ## Search Command ##
269
403
 
270
404
  This setting allows configuration of the IMAP search command sent to the server. This still defaults 'UNSEEN'. You may find that 'NEW' works better for you.
271
405
 
272
- ## IMAP Server Configuration ##
273
-
274
- You can set per-mailbox configuration for the IMAP server's `host` (default: 'imap.gmail.com'), `port` (default: 993), `ssl` (default: true), and `start_tls` (default: false).
275
-
276
- If you want to set additional options for IMAP SSL you can pass a YAML hash to match [SSLContext#set_params](http://docs.ruby-lang.org/en/2.2.0/OpenSSL/SSL/SSLContext.html#method-i-set_params). If you set `verify_mode` to `:none` it'll replace with the appropriate constant.
277
-
278
- If you're seeing the error `Please log in via your web browser: https://support.google.com/mail/accounts/answer/78754 (Failure)`, you need to configure your Gmail account to allow less secure apps to access it: https://support.google.com/accounts/answer/6010255.
279
-
280
406
  ## Running in Production ##
281
407
 
282
408
  I suggest running with either upstart or init.d. Check out this wiki page for some example scripts for both: https://github.com/tpitale/mail_room/wiki/Init-Scripts-for-Running-mail_room
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -31,7 +31,7 @@ module MailRoom
31
31
  # Any subsequent failure in the instance which gets the lock will be dealt
32
32
  # with by the expiration, at which time another instance can pick up the
33
33
  # message and try again.
34
- client.set(key, 1, {:nx => true, :ex => expiration})
34
+ client.set(key, 1, nx: true, ex: expiration)
35
35
  end
36
36
 
37
37
  private
data/lib/mail_room/cli.rb CHANGED
@@ -42,7 +42,7 @@ module MailRoom
42
42
  end.parse!(args)
43
43
 
44
44
  self.configuration = Configuration.new(options)
45
- self.coordinator = Coordinator.new(configuration.mailboxes)
45
+ self.coordinator = Coordinator.new(configuration.mailboxes, configuration.health_check)
46
46
  end
47
47
 
48
48
  # Start the coordinator running, sets up signal traps
@@ -57,7 +57,7 @@ module MailRoom
57
57
 
58
58
  coordinator.run
59
59
  rescue Exception => e # not just Errors, but includes lower-level Exceptions
60
- CrashHandler.new(error: e, format: @options[:exit_error_format]).handle
60
+ CrashHandler.new.handle(e, @options[:exit_error_format])
61
61
  exit
62
62
  end
63
63
  end
@@ -4,7 +4,7 @@ module MailRoom
4
4
  # Wraps configuration for a set of individual mailboxes with global config
5
5
  # @author Tony Pitale
6
6
  class Configuration
7
- attr_accessor :mailboxes, :log_path, :quiet
7
+ attr_accessor :mailboxes, :log_path, :quiet, :health_check
8
8
 
9
9
  # Initialize a new configuration of mailboxes
10
10
  def initialize(options={})
@@ -18,6 +18,7 @@ module MailRoom
18
18
  config_file = YAML.load(erb.result)
19
19
 
20
20
  set_mailboxes(config_file[:mailboxes])
21
+ set_health_check(config_file[:health_check])
21
22
  rescue => e
22
23
  raise e unless quiet
23
24
  end
@@ -32,5 +33,14 @@ module MailRoom
32
33
  self.mailboxes << Mailbox.new(attributes)
33
34
  end
34
35
  end
36
+
37
+ # Builds the health checker from YAML configuration
38
+ #
39
+ # @param health_check_config nil or a Hash containing :address and :port
40
+ def set_health_check(health_check_config)
41
+ return unless health_check_config
42
+
43
+ self.health_check = HealthCheck.new(health_check_config)
44
+ end
35
45
  end
36
46
  end
@@ -1,195 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module MailRoom
2
4
  class Connection
5
+ attr_reader :mailbox, :new_message_handler
6
+
3
7
  def initialize(mailbox)
4
8
  @mailbox = mailbox
5
-
6
- # log in and set the mailbox
7
- reset
8
- setup
9
+ @stopped = false
9
10
  end
10
11
 
11
12
  def on_new_message(&block)
12
13
  @new_message_handler = block
13
14
  end
14
15
 
15
- # is the connection logged in?
16
- # @return [Boolean]
17
- def logged_in?
18
- @logged_in
19
- end
20
-
21
- # is the connection blocked idling?
22
- # @return [Boolean]
23
- def idling?
24
- @idling
25
- end
26
-
27
- # is the imap connection closed?
28
- # @return [Boolean]
29
- def disconnected?
30
- @imap.disconnected?
31
- end
32
-
33
- # is the connection ready to idle?
34
- # @return [Boolean]
35
- def ready_to_idle?
36
- logged_in? && !idling?
37
- end
38
-
39
- def quit
40
- stop_idling
41
- reset
16
+ def stopped?
17
+ @stopped
42
18
  end
43
19
 
44
20
  def wait
45
- begin
46
- # in case we missed any between idles
47
- process_mailbox
48
-
49
- idle
50
-
51
- process_mailbox
52
- rescue Net::IMAP::Error, IOError
53
- @mailbox.logger.warn({ context: @mailbox.context, action: "Disconnected. Resetting..." })
54
- reset
55
- setup
56
- end
57
- end
58
-
59
- private
60
-
61
- def reset
62
- @imap = nil
63
- @logged_in = false
64
- @idling = false
65
- end
66
-
67
- def setup
68
- @mailbox.logger.info({ context: @mailbox.context, action: "Starting TLS session" })
69
- start_tls
70
-
71
- @mailbox.logger.info({ context: @mailbox.context, action: "Logging into mailbox" })
72
- log_in
73
-
74
- @mailbox.logger.info({ context: @mailbox.context, action: "Setting mailbox" })
75
- set_mailbox
76
- end
77
-
78
- # build a net/imap connection to google imap
79
- def imap
80
- @imap ||= Net::IMAP.new(@mailbox.host, :port => @mailbox.port, :ssl => @mailbox.ssl_options)
81
- end
82
-
83
- # start a TLS session
84
- def start_tls
85
- imap.starttls if @mailbox.start_tls
86
- end
87
-
88
- # send the imap login command to google
89
- def log_in
90
- imap.login(@mailbox.email, @mailbox.password)
91
- @logged_in = true
92
- end
93
-
94
- # select the mailbox name we want to use
95
- def set_mailbox
96
- imap.select(@mailbox.name) if logged_in?
97
- end
98
-
99
- # is the response for a new message?
100
- # @param response [Net::IMAP::TaggedResponse] the imap response from idle
101
- # @return [Boolean]
102
- def message_exists?(response)
103
- response.respond_to?(:name) && response.name == 'EXISTS'
104
- end
105
-
106
- # @private
107
- def idle_handler
108
- lambda {|response| imap.idle_done if message_exists?(response)}
109
- end
110
-
111
- # maintain an imap idle connection
112
- def idle
113
- return unless ready_to_idle?
114
-
115
- @mailbox.logger.info({ context: @mailbox.context, action: "Idling" })
116
- @idling = true
117
-
118
- imap.idle(@mailbox.idle_timeout, &idle_handler)
119
- ensure
120
- @idling = false
121
- end
122
-
123
- # trigger the idle to finish and wait for the thread to finish
124
- def stop_idling
125
- return unless idling?
126
-
127
- imap.idle_done
128
-
129
- # idling_thread.join
130
- # self.idling_thread = nil
131
- end
132
-
133
- def process_mailbox
134
- return unless @new_message_handler
135
- @mailbox.logger.info({ context: @mailbox.context, action: "Processing started" })
136
-
137
- msgs = new_messages
138
-
139
- any_deletions = msgs.
140
- # deliver each new message, collect success
141
- map(&@new_message_handler).
142
- # include messages with success
143
- zip(msgs).
144
- # filter failed deliveries, collect message
145
- select(&:first).map(&:last).
146
- # scrub delivered messages
147
- map { |message| scrub(message) }.
148
- any?
149
-
150
- imap.expunge if @mailbox.expunge_deleted && any_deletions
151
- end
152
-
153
- def scrub(message)
154
- if @mailbox.delete_after_delivery
155
- imap.store(message.seqno, "+FLAGS", [Net::IMAP::DELETED])
156
- true
157
- end
158
- end
159
-
160
- # @private
161
- # fetch all messages for the new message ids
162
- def new_messages
163
- # Both of these calls may results in
164
- # imap raising an EOFError, we handle
165
- # this exception in the watcher
166
- messages_for_ids(new_message_ids)
21
+ raise NotImplementedError
167
22
  end
168
23
 
169
- # TODO: label messages?
170
- # @imap.store(id, "+X-GM-LABELS", [label])
171
-
172
- # @private
173
- # search for all new (unseen) message ids
174
- # @return [Array<Integer>] message ids
175
- def new_message_ids
176
- # uid_search still leaves messages UNSEEN
177
- all_unread = @imap.uid_search(@mailbox.search_command)
178
-
179
- to_deliver = all_unread.select { |uid| @mailbox.deliver?(uid) }
180
- @mailbox.logger.info({ context: @mailbox.context, action: "Getting new messages", unread: {count: all_unread.count, ids: all_unread}, to_be_delivered: { count: to_deliver.count, ids: all_unread } })
181
- to_deliver
182
- end
183
-
184
- # @private
185
- # fetch the email for all given ids in RFC822 format
186
- # @param ids [Array<Integer>] list of message ids
187
- # @return [Array<Net::IMAP::FetchData>] the net/imap messages for the given ids
188
- def messages_for_ids(uids)
189
- return [] if uids.empty?
190
-
191
- # uid_fetch marks as SEEN, will not be re-fetched for UNSEEN
192
- imap.uid_fetch(uids, "RFC822")
24
+ def quit
25
+ @stopped = true
193
26
  end
194
27
  end
195
28
  end
@@ -2,13 +2,15 @@ module MailRoom
2
2
  # Coordinate the mailbox watchers
3
3
  # @author Tony Pitale
4
4
  class Coordinator
5
- attr_accessor :watchers, :running
5
+ attr_accessor :watchers, :running, :health_check
6
6
 
7
7
  # build watchers for a set of mailboxes
8
8
  # @params mailboxes [Array<MailRoom::Mailbox>] mailboxes to be watched
9
- def initialize(mailboxes)
9
+ # @params health_check <MailRoom::HealthCheck> health checker to run
10
+ def initialize(mailboxes, health_check = nil)
10
11
  self.watchers = []
11
12
 
13
+ @health_check = health_check
12
14
  mailboxes.each {|box| self.watchers << MailboxWatcher.new(box)}
13
15
  end
14
16
 
@@ -16,10 +18,11 @@ module MailRoom
16
18
 
17
19
  # start each of the watchers to running
18
20
  def run
21
+ health_check&.run
19
22
  watchers.each(&:run)
20
-
23
+
21
24
  self.running = true
22
-
25
+
23
26
  sleep_while_running
24
27
  ensure
25
28
  quit
@@ -27,6 +30,7 @@ module MailRoom
27
30
 
28
31
  # quit each of the watchers when we're done running
29
32
  def quit
33
+ health_check&.quit
30
34
  watchers.each(&:quit)
31
35
  end
32
36
 
@@ -1,30 +1,26 @@
1
+ require 'date'
1
2
 
2
3
  module MailRoom
3
4
  class CrashHandler
5
+ SUPPORTED_FORMATS = %w[json none]
4
6
 
5
- attr_reader :error, :format
6
-
7
- SUPPORTED_FORMATS = %w[json plain]
8
-
9
- def initialize(error:, format:)
10
- @error = error
11
- @format = format
7
+ def initialize(stream=STDOUT)
8
+ @stream = stream
12
9
  end
13
10
 
14
- def handle
11
+ def handle(error, format)
15
12
  if format == 'json'
16
- puts json
13
+ @stream.puts json(error)
17
14
  return
18
15
  end
19
16
 
20
- # 'plain' is equivalent to outputting the error into stdout as-is
21
17
  raise error
22
18
  end
23
19
 
24
20
  private
25
21
 
26
- def json
27
- { time: Time.now, severity: :fatal, message: error.message, backtrace: error.backtrace }.to_json
22
+ def json(error)
23
+ { time: DateTime.now.iso8601(3), severity: :fatal, message: error.message, backtrace: error.backtrace }.to_json
28
24
  end
29
25
  end
30
26
  end
@@ -24,7 +24,7 @@ module MailRoom
24
24
  # Trigger `LetterOpener` to deliver our message
25
25
  # @param message [String] the email message as a string, RFC822 format
26
26
  def deliver(message)
27
- method = ::LetterOpener::DeliveryMethod.new(:location => @delivery_options.location)
27
+ method = ::LetterOpener::DeliveryMethod.new(location: @delivery_options.location)
28
28
  method.deliver!(Mail.read_from_string(message))
29
29
 
30
30
  true
@@ -1,11 +1,12 @@
1
1
  require 'faraday'
2
+ require "mail_room/jwt"
2
3
 
3
4
  module MailRoom
4
5
  module Delivery
5
6
  # Postback Delivery method
6
7
  # @author Tony Pitale
7
8
  class Postback
8
- Options = Struct.new(:url, :token, :username, :password, :logger, :content_type) do
9
+ Options = Struct.new(:url, :token, :username, :password, :logger, :content_type, :jwt) do
9
10
  def initialize(mailbox)
10
11
  url =
11
12
  mailbox.delivery_url ||
@@ -17,6 +18,8 @@ module MailRoom
17
18
  mailbox.delivery_options[:delivery_token] ||
18
19
  mailbox.delivery_options[:token]
19
20
 
21
+ jwt = initialize_jwt(mailbox.delivery_options)
22
+
20
23
  username = mailbox.delivery_options[:username]
21
24
  password = mailbox.delivery_options[:password]
22
25
 
@@ -24,16 +27,31 @@ module MailRoom
24
27
 
25
28
  content_type = mailbox.delivery_options[:content_type]
26
29
 
27
- super(url, token, username, password, logger, content_type)
30
+ super(url, token, username, password, logger, content_type, jwt)
28
31
  end
29
32
 
30
33
  def token_auth?
31
34
  !self[:token].nil?
32
35
  end
33
36
 
37
+ def jwt_auth?
38
+ self[:jwt].valid?
39
+ end
40
+
34
41
  def basic_auth?
35
42
  !self[:username].nil? && !self[:password].nil?
36
43
  end
44
+
45
+ private
46
+
47
+ def initialize_jwt(delivery_options)
48
+ ::MailRoom::JWT.new(
49
+ header: delivery_options[:jwt_auth_header],
50
+ secret_path: delivery_options[:jwt_secret_path],
51
+ algorithm: delivery_options[:jwt_algorithm],
52
+ issuer: delivery_options[:jwt_issuer]
53
+ )
54
+ end
37
55
  end
38
56
 
39
57
  # Build a new delivery, hold the delivery options
@@ -60,13 +78,27 @@ module MailRoom
60
78
  connection.post do |request|
61
79
  request.url @delivery_options.url
62
80
  request.body = message
63
- # request.options[:timeout] = 3
64
- request.headers['Content-Type'] = @delivery_options.content_type unless @delivery_options.content_type.nil?
81
+ config_request_content_type(request)
82
+ config_request_jwt_auth(request)
65
83
  end
66
84
 
67
85
  @delivery_options.logger.info({ delivery_method: 'Postback', action: 'message pushed', url: @delivery_options.url })
68
86
  true
69
87
  end
88
+
89
+ private
90
+
91
+ def config_request_content_type(request)
92
+ return if @delivery_options.content_type.nil?
93
+
94
+ request.headers['Content-Type'] = @delivery_options.content_type
95
+ end
96
+
97
+ def config_request_jwt_auth(request)
98
+ return unless @delivery_options.jwt_auth?
99
+
100
+ request.headers[@delivery_options.jwt.header] = @delivery_options.jwt.token
101
+ end
70
102
  end
71
103
  end
72
104
  end
@@ -8,16 +8,17 @@ module MailRoom
8
8
  # Sidekiq Delivery method
9
9
  # @author Douwe Maan
10
10
  class Sidekiq
11
- Options = Struct.new(:redis_url, :namespace, :sentinels, :queue, :worker, :logger) do
11
+ Options = Struct.new(:redis_url, :namespace, :sentinels, :queue, :worker, :logger, :redis_db) do
12
12
  def initialize(mailbox)
13
13
  redis_url = mailbox.delivery_options[:redis_url] || "redis://localhost:6379"
14
+ redis_db = mailbox.delivery_options[:redis_db] || 0
14
15
  namespace = mailbox.delivery_options[:namespace]
15
16
  sentinels = mailbox.delivery_options[:sentinels]
16
17
  queue = mailbox.delivery_options[:queue] || "default"
17
18
  worker = mailbox.delivery_options[:worker]
18
19
  logger = mailbox.logger
19
20
 
20
- super(redis_url, namespace, sentinels, queue, worker, logger)
21
+ super(redis_url, namespace, sentinels, queue, worker, logger, redis_db)
21
22
  end
22
23
  end
23
24
 
@@ -45,7 +46,7 @@ module MailRoom
45
46
  def client
46
47
  @client ||= begin
47
48
  sentinels = options.sentinels
48
- redis_options = { url: options.redis_url }
49
+ redis_options = { url: options.redis_url, db: options.redis_db }
49
50
  redis_options[:sentinels] = sentinels if sentinels
50
51
 
51
52
  redis = ::Redis.new(redis_options)