mail_room 0.10.1 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -111,10 +111,23 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
111
111
  :client_id: ABCDE
112
112
  :client_secret: YOUR-SECRET-HERE
113
113
  :poll_interval: 60
114
+ :azure_ad_endpoint: https://login.microsoftonline.com
115
+ :graph_endpoint: https://graph.microsoft.com
114
116
  :delivery_method: sidekiq
115
117
  :delivery_options:
116
118
  :redis_url: redis://localhost:6379
117
119
  :worker: EmailReceiverWorker
120
+ -
121
+ :email: "user8@gmail.com"
122
+ :password: "password"
123
+ :name: "inbox"
124
+ :delivery_method: postback
125
+ :delivery_options:
126
+ :delivery_url: "http://localhost:3000/inbox"
127
+ :jwt_auth_header: "Mailroom-Api-Request"
128
+ :jwt_issuer: "mailroom"
129
+ :jwt_algorithm: "HS256"
130
+ :jwt_secret_path: "/etc/secrets/mailroom/.mailroom_secret"
118
131
  ```
119
132
 
120
133
  **Note:** If using `delete_after_delivery`, you also probably want to use
@@ -135,11 +148,11 @@ If you're seeing the error `Please log in via your web browser: https://support.
135
148
  ### Microsoft Graph configuration
136
149
 
137
150
  To use the Microsoft Graph API instead of IMAP to read e-mail, you will
138
- need to create an application in the Azure Active Directory. See the
139
- [Microsoft instructions](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app) for more details:
151
+ need to create an application in Microsoft Entra ID (formerly known as Azure Active Directory). See the
152
+ [Microsoft instructions](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) for more details:
140
153
 
141
154
  1. Sign in to the [Azure portal](https://portal.azure.com).
142
- 1. Search for and select `Azure Active Directory`.
155
+ 1. Search for and select `Microsoft Entra ID`.
143
156
  1. Under `Manage`, select `App registrations` > `New registration`.
144
157
  1. Enter a `Name` for your application, such as `MailRoom`. Users of your app might see this name, and you can change it later.
145
158
  1. If `Supported account types` is listed, select the appropriate option.
@@ -186,6 +199,25 @@ Fill in `inbox_options` with these values:
186
199
  By default, MailRoom will poll for new messages every 60 seconds. `poll_interval` configures the number of
187
200
  seconds to poll. Setting the value to 0 or under will default to 60 seconds.
188
201
 
202
+ ### Alternative Azure cloud deployments
203
+
204
+ MailRoom will default to using the standard Azure HTTPS endpoints. To
205
+ configure MailRoom with Microsoft Cloud for US Government or other
206
+ [national cloud deployments](https://docs.microsoft.com/en-us/graph/deployments), set
207
+ the `azure_ad_endpoint` and `graph_endpoint` accordingly. For example,
208
+ for Microsoft Cloud for US Government:
209
+
210
+ ```yaml
211
+ :inbox_method: microsoft_graph
212
+ :inbox_options:
213
+ :tenant_id: 12345
214
+ :client_id: ABCDE
215
+ :client_secret: YOUR-SECRET-HERE
216
+ :poll_interval: 60
217
+ :azure_ad_endpoint: https://login.microsoftonline.us
218
+ :graph_endpoint: https://graph.microsoft.us
219
+ ```
220
+
189
221
  ## delivery_method ##
190
222
 
191
223
  ### postback ###
@@ -215,7 +247,7 @@ Delivery options:
215
247
  Required, defaults to `redis://localhost:6379`.
216
248
  - **sentinels**: A list of sentinels servers used to provide HA to Redis. (see [Sentinel Support](#sentinel-support))
217
249
  Optional.
218
- - **namespace**: The Redis namespace Sidekiq works under. Use the same Redis namespace that's used to configure Sidekiq.
250
+ - **namespace**: [DEPRECATED] The Redis namespace Sidekiq works under. Use the same Redis namespace that's used to configure Sidekiq.
219
251
  Optional.
220
252
  - **queue**: The Sidekiq queue the job is pushed onto. Make sure Sidekiq actually reads off this queue.
221
253
  Required, defaults to `default`.
@@ -312,8 +344,8 @@ And finally, configure MailRoom to use the postback configuration with the optio
312
344
  :delivery_method: postback
313
345
  :delivery_options:
314
346
  :delivery_url: https://example.com/rails/action_mailbox/relay/inbound_emails
315
- :delivery_username: actionmailbox
316
- :delivery_password: <INGRESS_PASSWORD>
347
+ :username: actionmailbox
348
+ :password: <INGRESS_PASSWORD>
317
349
  ```
318
350
 
319
351
  ## Receiving `postback` in Rails ##
@@ -359,7 +391,7 @@ When running multiple instances of MailRoom against a single mailbox, to try to
359
391
  :arbitration_options:
360
392
  # The Redis server to connect with. Defaults to redis://localhost:6379.
361
393
  :redis_url: redis://redis.example.com:6379
362
- # The Redis namespace to house the Redis keys under. Optional.
394
+ # [DEPRECATED] The Redis namespace to house the Redis keys under. Optional.
363
395
  :namespace: mail_room
364
396
  -
365
397
  :email: "user2@gmail.com"
@@ -379,7 +411,7 @@ When running multiple instances of MailRoom against a single mailbox, to try to
379
411
  -
380
412
  :host: 127.0.0.1
381
413
  :port: 26379
382
- # The Redis namespace to house the Redis keys under. Optional.
414
+ # [DEPRECATED] The Redis namespace to house the Redis keys under. Optional.
383
415
  :namespace: mail_room
384
416
  ```
385
417
 
@@ -422,13 +454,3 @@ respectively and MailRoom will log there.
422
454
  4. Push to the branch (`git push origin my-new-feature`)
423
455
  5. Create new Pull Request
424
456
  6. If accepted, ask for commit rights
425
-
426
- ## TODO ##
427
-
428
- 1. specs, this is just a (working) proof of concept √
429
- 2. finish code for POSTing to callback with auth √
430
- 3. accept mailbox configuration for one account directly on the commandline; or ask for it
431
- 4. add example rails endpoint, with auth examples
432
- 5. add example configs for upstart/init.d √
433
- 6. log to stdout √
434
- 7. add a development mode that opens in letter_opener by ryanb √
@@ -9,6 +9,13 @@ module MailRoom
9
9
  namespace = mailbox.arbitration_options[:namespace]
10
10
  sentinels = mailbox.arbitration_options[:sentinels]
11
11
 
12
+ if namespace
13
+ warn <<~MSG
14
+ Redis namespaces are deprecated. This option will be ignored in future versions.
15
+ See https://github.com/sidekiq/sidekiq/issues/2586 for more details."
16
+ MSG
17
+ end
18
+
12
19
  super(redis_url, namespace, sentinels)
13
20
  end
14
21
  end
@@ -31,7 +38,7 @@ module MailRoom
31
38
  # Any subsequent failure in the instance which gets the lock will be dealt
32
39
  # with by the expiration, at which time another instance can pick up the
33
40
  # message and try again.
34
- client.set(key, 1, {nx: true, ex: expiration})
41
+ client.set(key, 1, nx: true, ex: expiration)
35
42
  end
36
43
 
37
44
  private
@@ -6,16 +6,23 @@ module MailRoom
6
6
 
7
7
  def initialize(mailbox)
8
8
  @mailbox = mailbox
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
 
16
+ def stopped?
17
+ @stopped
18
+ end
19
+
15
20
  def wait
16
21
  raise NotImplementedError
17
22
  end
18
23
 
19
- def quit; end
24
+ def quit
25
+ @stopped = true
26
+ end
20
27
  end
21
28
  end
@@ -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,23 +18,44 @@ module MailRoom
17
18
  mailbox.delivery_options[:delivery_token] ||
18
19
  mailbox.delivery_options[:token]
19
20
 
20
- username = mailbox.delivery_options[:username]
21
- password = mailbox.delivery_options[:password]
21
+ jwt = initialize_jwt(mailbox.delivery_options)
22
+
23
+ username =
24
+ mailbox.delivery_options[:username] ||
25
+ mailbox.delivery_options[:delivery_username]
26
+ password =
27
+ mailbox.delivery_options[:password] ||
28
+ mailbox.delivery_options[:delivery_password]
22
29
 
23
30
  logger = mailbox.logger
24
31
 
25
32
  content_type = mailbox.delivery_options[:content_type]
26
33
 
27
- super(url, token, username, password, logger, content_type)
34
+ super(url, token, username, password, logger, content_type, jwt)
28
35
  end
29
36
 
30
37
  def token_auth?
31
38
  !self[:token].nil?
32
39
  end
33
40
 
41
+ def jwt_auth?
42
+ self[:jwt].valid?
43
+ end
44
+
34
45
  def basic_auth?
35
46
  !self[:username].nil? && !self[:password].nil?
36
47
  end
48
+
49
+ private
50
+
51
+ def initialize_jwt(delivery_options)
52
+ ::MailRoom::JWT.new(
53
+ header: delivery_options[:jwt_auth_header],
54
+ secret_path: delivery_options[:jwt_secret_path],
55
+ algorithm: delivery_options[:jwt_algorithm],
56
+ issuer: delivery_options[:jwt_issuer]
57
+ )
58
+ end
37
59
  end
38
60
 
39
61
  # Build a new delivery, hold the delivery options
@@ -49,24 +71,62 @@ module MailRoom
49
71
  connection = Faraday.new
50
72
 
51
73
  if @delivery_options.token_auth?
52
- connection.token_auth @delivery_options.token
74
+ config_token_auth(connection)
53
75
  elsif @delivery_options.basic_auth?
54
- connection.basic_auth(
55
- @delivery_options.username,
56
- @delivery_options.password
57
- )
76
+ config_basic_auth(connection)
58
77
  end
59
78
 
60
79
  connection.post do |request|
61
80
  request.url @delivery_options.url
62
81
  request.body = message
63
- # request.options[:timeout] = 3
64
- request.headers['Content-Type'] = @delivery_options.content_type unless @delivery_options.content_type.nil?
82
+ config_request_content_type(request)
83
+ config_request_jwt_auth(request)
65
84
  end
66
85
 
67
86
  @delivery_options.logger.info({ delivery_method: 'Postback', action: 'message pushed', url: @delivery_options.url })
68
87
  true
69
88
  end
89
+
90
+ private
91
+
92
+ def config_request_content_type(request)
93
+ return if @delivery_options.content_type.nil?
94
+
95
+ request.headers['Content-Type'] = @delivery_options.content_type
96
+ end
97
+
98
+ def config_request_jwt_auth(request)
99
+ return unless @delivery_options.jwt_auth?
100
+
101
+ request.headers[@delivery_options.jwt.header] = @delivery_options.jwt.token
102
+ end
103
+
104
+ def config_token_auth(connection)
105
+ # connection.token_auth was removed in Faraday v2 in favor of connection.request(:authorization, 'Token', token)
106
+ if defined?(connection.token_auth)
107
+ connection.token_auth @delivery_options.token
108
+ else
109
+ connection.request(
110
+ :authorization, 'Token',
111
+ @delivery_options.token
112
+ )
113
+ end
114
+ end
115
+
116
+ def config_basic_auth(connection)
117
+ if defined?(connection.basic_auth)
118
+ connection.basic_auth(
119
+ @delivery_options.username,
120
+ @delivery_options.password
121
+ )
122
+ else
123
+ connection.request(
124
+ :authorization, :basic,
125
+ @delivery_options.username,
126
+ @delivery_options.password
127
+ )
128
+ end
129
+ end
70
130
  end
71
131
  end
72
132
  end
@@ -1,5 +1,6 @@
1
1
  require 'pg'
2
2
  require 'json'
3
+ require 'charlock_holmes'
3
4
 
4
5
  module MailRoom
5
6
  module Delivery
@@ -34,7 +35,7 @@ module MailRoom
34
35
  # deliver the message by pushing it onto the configured Sidekiq queue
35
36
  # @param message [String] the email message as a string, RFC822 format
36
37
  def deliver(message)
37
- queue_job(message)
38
+ queue_job(utf8_encode_message(message))
38
39
  @options.logger.info({ delivery_method: 'Que', action: 'message pushed' })
39
40
  end
40
41
 
@@ -58,6 +59,19 @@ module MailRoom
58
59
 
59
60
  connection.exec(sql, [options.priority, options.job_class, options.queue, JSON.dump(args)])
60
61
  end
62
+
63
+ def utf8_encode_message(message)
64
+ message = message.dup
65
+
66
+ message.force_encoding("UTF-8")
67
+ return message if message.valid_encoding?
68
+
69
+ detection = CharlockHolmes::EncodingDetector.detect(message)
70
+ return message unless detection && detection[:encoding]
71
+
72
+ # Convert non-UTF-8 body UTF-8 so it can be dumped as JSON.
73
+ CharlockHolmes::Converter.convert(message, detection[:encoding], 'UTF-8')
74
+ end
61
75
  end
62
76
  end
63
77
  end
@@ -18,6 +18,13 @@ module MailRoom
18
18
  worker = mailbox.delivery_options[:worker]
19
19
  logger = mailbox.logger
20
20
 
21
+ if namespace
22
+ warn <<~MSG
23
+ Redis namespaces are deprecated. This option will be ignored in future versions.
24
+ See https://github.com/sidekiq/sidekiq/issues/2586 for more details."
25
+ MSG
26
+ end
27
+
21
28
  super(redis_url, namespace, sentinels, queue, worker, logger, redis_db)
22
29
  end
23
30
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'securerandom'
5
+ require 'jwt'
6
+ require 'base64'
7
+
8
+ module MailRoom
9
+ # Responsible for validating and generating JWT token
10
+ class JWT
11
+ DEFAULT_ISSUER = 'mailroom'
12
+ DEFAULT_ALGORITHM = 'HS256'
13
+
14
+ attr_reader :header, :secret_path, :issuer, :algorithm
15
+
16
+ def initialize(header:, secret_path:, issuer:, algorithm:)
17
+ @header = header
18
+ @secret_path = secret_path
19
+ @issuer = issuer || DEFAULT_ISSUER
20
+ @algorithm = algorithm || DEFAULT_ALGORITHM
21
+ end
22
+
23
+ def valid?
24
+ [@header, @secret_path, @issuer, @algorithm].none?(&:nil?)
25
+ end
26
+
27
+ def token
28
+ return nil unless valid?
29
+
30
+ secret = Base64.strict_decode64(File.read(@secret_path).chomp)
31
+ payload = {
32
+ nonce: SecureRandom.hex(12),
33
+ iat: Time.now.to_i, # https://github.com/jwt/ruby-jwt#issued-at-claim
34
+ iss: @issuer
35
+ }
36
+ ::JWT.encode payload, secret, @algorithm
37
+ end
38
+ end
39
+ end
@@ -6,7 +6,6 @@ require 'oauth2'
6
6
  module MailRoom
7
7
  module MicrosoftGraph
8
8
  class Connection < MailRoom::Connection
9
- SCOPE = 'https://graph.microsoft.com/.default'
10
9
  NEXT_PAGE_KEY = '@odata.nextLink'
11
10
  DEFAULT_POLL_INTERVAL_S = 60
12
11
 
@@ -22,6 +21,8 @@ module MailRoom
22
21
  end
23
22
 
24
23
  def wait
24
+ return if stopped?
25
+
25
26
  process_mailbox
26
27
 
27
28
  @throttled_count = 0
@@ -42,17 +43,30 @@ module MailRoom
42
43
  private
43
44
 
44
45
  def wait_for_new_messages
45
- sleep poll_interval
46
+ sleep_while_running(poll_interval)
46
47
  end
47
48
 
48
49
  def backoff
49
- sleep backoff_secs
50
+ sleep_while_running(backoff_secs)
50
51
  end
51
52
 
52
53
  def backoff_secs
53
54
  [60 * 10, 2**throttled_count].min
54
55
  end
55
56
 
57
+ # Unless wake up periodically, we won't notice that the thread was stopped
58
+ # if we sleep the entire interval.
59
+ def sleep_while_running(sleep_interval)
60
+ sleep_interval.times do
61
+ do_sleep(1)
62
+ return if stopped?
63
+ end
64
+ end
65
+
66
+ def do_sleep(interval)
67
+ sleep(interval)
68
+ end
69
+
56
70
  def reset
57
71
  @token = nil
58
72
  @throttled_count = 0
@@ -61,12 +75,12 @@ module MailRoom
61
75
  def setup
62
76
  @mailbox.logger.info({ context: @mailbox.context, action: 'Retrieving OAuth2 token...' })
63
77
 
64
- @token = client.client_credentials.get_token({ scope: SCOPE })
78
+ @token = client.client_credentials.get_token({ scope: scope })
65
79
  end
66
80
 
67
81
  def client
68
82
  @client ||= OAuth2::Client.new(client_id, client_secret,
69
- site: 'https://login.microsoftonline.com',
83
+ site: azure_ad_endpoint,
70
84
  authorize_url: "/#{tenant_id}/oauth2/v2.0/authorize",
71
85
  token_url: "/#{tenant_id}/oauth2/v2.0/token",
72
86
  auth_scheme: :basic_auth)
@@ -192,7 +206,7 @@ module MailRoom
192
206
  end
193
207
 
194
208
  def base_url
195
- "https://graph.microsoft.com/v1.0/users/#{mailbox.email}/mailFolders/#{mailbox.name}/messages"
209
+ "#{graph_endpoint}/v1.0/users/#{mailbox.email}/mailFolders/#{mailbox.name}/messages"
196
210
  end
197
211
 
198
212
  def unread_messages_url
@@ -201,7 +215,7 @@ module MailRoom
201
215
 
202
216
  def msg_url(id)
203
217
  # Attempting to use the base_url fails with "The OData request is not supported"
204
- "https://graph.microsoft.com/v1.0/users/#{mailbox.email}/messages/#{id}"
218
+ "#{graph_endpoint}/v1.0/users/#{mailbox.email}/messages/#{id}"
205
219
  end
206
220
 
207
221
  def rfc822_msg_url(id)
@@ -212,6 +226,18 @@ module MailRoom
212
226
  def log_exception(message, exception)
213
227
  @mailbox.logger.warn({ context: @mailbox.context, message: message, exception: exception.to_s })
214
228
  end
229
+
230
+ def scope
231
+ "#{graph_endpoint}/.default"
232
+ end
233
+
234
+ def graph_endpoint
235
+ inbox_options[:graph_endpoint] || 'https://graph.microsoft.com'
236
+ end
237
+
238
+ def azure_ad_endpoint
239
+ inbox_options[:azure_ad_endpoint] || 'https://login.microsoftonline.com'
240
+ end
215
241
  end
216
242
  end
217
243
  end
@@ -1,4 +1,4 @@
1
1
  module MailRoom
2
2
  # Current version of MailRoom gem
3
- VERSION = "0.10.1"
3
+ VERSION = "0.11.1"
4
4
  end
data/mail_room.gemspec CHANGED
@@ -18,19 +18,20 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_dependency "net-imap", ">= 0.2.1"
21
- gem.add_dependency "oauth2", "~> 1.4.4"
21
+ gem.add_dependency "oauth2", [">= 1.4.4", "< 3"]
22
+ gem.add_dependency "jwt", ">= 2.0"
22
23
 
23
24
  gem.add_development_dependency "rake"
24
25
  gem.add_development_dependency "rspec", "~> 3.9"
25
26
  gem.add_development_dependency "rubocop", "~> 1.11"
26
- gem.add_development_dependency "mocha", "~> 1.11"
27
+ gem.add_development_dependency "mocha", "~> 2.0"
27
28
  gem.add_development_dependency "simplecov"
28
29
 
29
30
  # for testing delivery methods
30
31
  gem.add_development_dependency "faraday"
31
32
  gem.add_development_dependency "mail"
32
33
  gem.add_development_dependency "letter_opener"
33
- gem.add_development_dependency "redis", "~> 3.3.1"
34
+ gem.add_development_dependency "redis", "~> 4"
34
35
  gem.add_development_dependency "redis-namespace"
35
36
  gem.add_development_dependency "pg"
36
37
  gem.add_development_dependency "charlock_holmes"
@@ -0,0 +1 @@
1
+ aGVsbG93b3JsZA==
@@ -15,6 +15,7 @@ describe MailRoom::Arbitration::Redis do
15
15
 
16
16
  # Private, but we don't care.
17
17
  let(:redis) { subject.send(:client) }
18
+ let(:raw_client) { redis._client }
18
19
 
19
20
  describe '#deliver?' do
20
21
  context "when called the first time" do
@@ -95,7 +96,7 @@ describe MailRoom::Arbitration::Redis do
95
96
  it 'client has same specified url' do
96
97
  subject.deliver?(123)
97
98
 
98
- expect(redis.client.options[:url]).to eq redis_url
99
+ expect(raw_client.options[:url]).to eq redis_url
99
100
  end
100
101
 
101
102
  it 'client is a instance of Redis class' do
@@ -137,10 +138,10 @@ describe MailRoom::Arbitration::Redis do
137
138
  before { ::Redis::Client::Connector::Sentinel.any_instance.stubs(:resolve).returns(sentinels) }
138
139
 
139
140
  it 'client has same specified sentinel params' do
140
- expect(redis.client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
141
- expect(redis.client.options[:host]).to eq('sentinel-master')
142
- expect(redis.client.options[:password]).to eq('mypassword')
143
- expect(redis.client.options[:sentinels]).to eq(sentinels)
141
+ expect(raw_client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
142
+ expect(raw_client.options[:host]).to eq('sentinel-master')
143
+ expect(raw_client.options[:password]).to eq('mypassword')
144
+ expect(raw_client.options[:sentinels]).to eq(sentinels)
144
145
  end
145
146
  end
146
147
  end
@@ -4,12 +4,13 @@ require 'mail_room/delivery/letter_opener'
4
4
  describe MailRoom::Delivery::LetterOpener do
5
5
  describe '#deliver' do
6
6
  let(:mailbox) {build_mailbox(location: '/tmp/somewhere')}
7
- let(:delivery_method) {stub(:deliver!)}
7
+ let(:delivery_method) {stub}
8
8
  let(:mail) {stub}
9
9
 
10
10
  before :each do
11
11
  Mail.stubs(:read_from_string).returns(mail)
12
12
  ::LetterOpener::DeliveryMethod.stubs(:new).returns(delivery_method)
13
+ delivery_method.stubs(:deliver!)
13
14
  end
14
15
 
15
16
  it 'creates a new LetterOpener::DeliveryMethod' do
@@ -19,7 +19,8 @@ describe MailRoom::Delivery::Logger do
19
19
  let(:mailbox) {build_mailbox(log_path: '/var/log/mail-room.log')}
20
20
 
21
21
  it 'creates a new file to append to' do
22
- file = stub(:sync=)
22
+ file = stub
23
+ file.stubs(:sync=)
23
24
 
24
25
  File.expects(:open).with('/var/log/mail-room.log', 'a').returns(file)
25
26
  ::Logger.stubs(:new).with(file)
@@ -65,11 +65,10 @@ describe MailRoom::Delivery::Postback do
65
65
  }
66
66
  })}
67
67
 
68
-
69
68
  let(:delivery_options) {
70
69
  MailRoom::Delivery::Postback::Options.new(mailbox)
71
70
  }
72
-
71
+
73
72
  it 'posts the message with faraday' do
74
73
  connection = stub
75
74
  request = stub
@@ -82,10 +81,59 @@ describe MailRoom::Delivery::Postback do
82
81
  connection.expects(:basic_auth).with('user1', 'password123abc')
83
82
 
84
83
  MailRoom::Delivery::Postback.new(delivery_options).deliver('a message')
85
-
84
+
86
85
  expect(request.headers['Content-Type']).to eq('text/plain')
87
86
  end
88
87
  end
88
+
89
+ context 'with jwt token in the delivery options' do
90
+ let(:mailbox) {build_mailbox({
91
+ delivery_options: {
92
+ url: 'http://localhost/inbox',
93
+ jwt_auth_header: "Mailroom-Api-Request",
94
+ jwt_issuer: "mailroom",
95
+ jwt_algorithm: "HS256",
96
+ jwt_secret_path: "secret_path"
97
+ }
98
+ })}
99
+
100
+ let(:delivery_options) {
101
+ MailRoom::Delivery::Postback::Options.new(mailbox)
102
+ }
103
+
104
+ it 'posts the message with faraday' do
105
+ connection = stub
106
+ request = stub
107
+ Faraday.stubs(:new).returns(connection)
108
+
109
+ connection.expects(:post).yields(request).twice
110
+ request.stubs(:url)
111
+ request.stubs(:body=)
112
+ request.stubs(:headers).returns({})
113
+
114
+ jwt = stub
115
+ MailRoom::JWT.expects(:new).with(
116
+ header: 'Mailroom-Api-Request',
117
+ issuer: 'mailroom',
118
+ algorithm: 'HS256',
119
+ secret_path: 'secret_path'
120
+ ).returns(jwt)
121
+ jwt.stubs(:valid?).returns(true)
122
+ jwt.stubs(:header).returns('Mailroom-Api-Request')
123
+ jwt.stubs(:token).returns('a_jwt_token')
124
+
125
+ delivery = MailRoom::Delivery::Postback.new(delivery_options)
126
+
127
+ delivery.deliver('a message')
128
+ expect(request.headers['Mailroom-Api-Request']).to eql('a_jwt_token')
129
+
130
+ # A different jwt token for the second time
131
+ jwt.stubs(:token).returns('another_jwt_token')
132
+
133
+ delivery.deliver('another message')
134
+ expect(request.headers['Mailroom-Api-Request']).to eql('another_jwt_token')
135
+ end
136
+ end
89
137
  end
90
138
  end
91
139
  end