gitlab-mail_room 0.0.14 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6be406940356ef2cd8f9f0121c5d605cb4dabdcf1a8dba6a5d8ccc6726cc6977
4
- data.tar.gz: 55d0a8aece3f5ec5c69ded80c2de37b609e96d475767ea77bc42be4c9be6fa99
3
+ metadata.gz: b35546ba9ef63ad546144c97515d7203a56182abb48be0b4975061e7c8598555
4
+ data.tar.gz: c6d96b85320aeafd0b41004e6b606aad1a3642de8ebee52734becc92de387185
5
5
  SHA512:
6
- metadata.gz: 758daf7cb8ff1494f54f145400e9e46b93490a876c6a544268492c4cad3487b970798f9c73afaf63e9001420f8b08b861c7e8c0210c3eb86850f5576b687d29c
7
- data.tar.gz: 6d0b716a7fe2c8f0f2d1c4042ca1f5eb2a7056b27c67aaa9b9b86d3de1c6658fb8a1ee21ff33da1e7f1c298612a7a795610e543c42ed37e291a67830a38ddfa5
6
+ metadata.gz: 9732c479849c02606adfda10314f3cfd5d83a8c1283d4054b5464480a3eae20f1414e0db0147a8b8cf383fe0fd4d073fcc0f522377792a4fed0d64daa621ad6f
7
+ data.tar.gz: a7d5f829af0796d81deeb8b4b570c932723f0bcfb0d80f322e9bed02dddd809a286cac2beff486c199b992d3d93d1646f268e15b983f8e3e0eae6a8c0c36fb3c
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.7.2
1
+ 2.7.5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## mail_room 0.10.1 ##
2
+
3
+ * Fix db attribute on redis URL PR#130 - @jarkaK
4
+
1
5
  ## mail_room 0.10.0 ##
2
6
 
3
7
  * Remove imap backports
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,40 @@
1
+ ## Developer Certificate of Origin and License
2
+
3
+ By contributing to GitLab B.V., you accept and agree to the following terms and
4
+ conditions for your present and future contributions submitted to GitLab B.V.
5
+ Except for the license granted herein to GitLab B.V. and recipients of software
6
+ distributed by GitLab B.V., you reserve all right, title, and interest in and to
7
+ your Contributions.
8
+
9
+ All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/ce/legal/developer_certificate_of_origin](https://docs.gitlab.com/ce/legal/developer_certificate_of_origin).
10
+
11
+ _This notice should stay as the first item in the CONTRIBUTING.md file._
12
+
13
+ ## Code of conduct
14
+
15
+ As contributors and maintainers of this project, we pledge to respect all people
16
+ who contribute through reporting issues, posting feature requests, updating
17
+ documentation, submitting pull requests or patches, and other activities.
18
+
19
+ We are committed to making participation in this project a harassment-free
20
+ experience for everyone, regardless of level of experience, gender, gender
21
+ identity and expression, sexual orientation, disability, personal appearance,
22
+ body size, race, ethnicity, age, or religion.
23
+
24
+ Examples of unacceptable behavior by participants include the use of sexual
25
+ language or imagery, derogatory comments or personal attacks, trolling, public
26
+ or private harassment, insults, or other unprofessional conduct.
27
+
28
+ Project maintainers have the right and responsibility to remove, edit, or reject
29
+ comments, commits, code, wiki edits, issues, and other contributions that are
30
+ not aligned to this Code of Conduct. Project maintainers who do not follow the
31
+ Code of Conduct may be removed from the project team.
32
+
33
+ This code of conduct applies both within project spaces and in public spaces
34
+ when an individual is representing the project or its community.
35
+
36
+ Instances of abusive, harassing, or otherwise unacceptable behavior can be
37
+ reported by emailing contact@gitlab.com.
38
+
39
+ This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org), version 1.1.0,
40
+ available at [https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/).
data/README.md CHANGED
@@ -138,6 +138,17 @@ You will also need to install `faraday` or `letter_opener` if you use the `postb
138
138
  :delivery_options:
139
139
  :redis_url: redis://localhost:6379
140
140
  :worker: EmailReceiverWorker
141
+ -
142
+ :email: "user8@gmail.com"
143
+ :password: "password"
144
+ :name: "inbox"
145
+ :delivery_method: postback
146
+ :delivery_options:
147
+ :delivery_url: "http://localhost:3000/inbox"
148
+ :jwt_auth_header: "Mailroom-Api-Request"
149
+ :jwt_issuer: "mailroom"
150
+ :jwt_algorithm: "HS256"
151
+ :jwt_secret_path: "/etc/secrets/mailroom/.mailroom_secret"
141
152
  ```
142
153
 
143
154
  **Note:** If using `delete_after_delivery`, you also probably want to use
@@ -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
@@ -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,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
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'securerandom'
5
+
6
+ module MailRoom
7
+ # Responsible for validating and generating JWT token
8
+ class JWT
9
+ DEFAULT_ISSUER = 'mailroom'
10
+ DEFAULT_ALGORITHM = 'HS256'
11
+
12
+ attr_reader :header, :secret_path, :issuer, :algorithm
13
+
14
+ def initialize(header:, secret_path:, issuer:, algorithm:)
15
+ @header = header
16
+ @secret_path = secret_path
17
+ @issuer = issuer || DEFAULT_ISSUER
18
+ @algorithm = algorithm || DEFAULT_ALGORITHM
19
+ end
20
+
21
+ def valid?
22
+ [@header, @secret_path, @issuer, @algorithm].none?(&:nil?)
23
+ end
24
+
25
+ def token
26
+ return nil unless valid?
27
+
28
+ secret = Base64.strict_decode64(File.read(@secret_path).chomp)
29
+ payload = {
30
+ nonce: SecureRandom.hex(12),
31
+ iat: Time.now.to_i, # https://github.com/jwt/ruby-jwt#issued-at-claim
32
+ iss: @issuer
33
+ }
34
+ ::JWT.encode payload, secret, @algorithm
35
+ end
36
+ end
37
+ end
@@ -22,6 +22,8 @@ module MailRoom
22
22
  end
23
23
 
24
24
  def wait
25
+ return if stopped?
26
+
25
27
  process_mailbox
26
28
 
27
29
  @throttled_count = 0
@@ -42,17 +44,30 @@ module MailRoom
42
44
  private
43
45
 
44
46
  def wait_for_new_messages
45
- sleep poll_interval
47
+ sleep_while_running(poll_interval)
46
48
  end
47
49
 
48
50
  def backoff
49
- sleep backoff_secs
51
+ sleep_while_running(backoff_secs)
50
52
  end
51
53
 
52
54
  def backoff_secs
53
55
  [60 * 10, 2**throttled_count].min
54
56
  end
55
57
 
58
+ # Unless wake up periodically, we won't notice that the thread was stopped
59
+ # if we sleep the entire interval.
60
+ def sleep_while_running(sleep_interval)
61
+ sleep_interval.times do
62
+ do_sleep(1)
63
+ return if stopped?
64
+ end
65
+ end
66
+
67
+ def do_sleep(interval)
68
+ sleep(interval)
69
+ end
70
+
56
71
  def reset
57
72
  @token = nil
58
73
  @throttled_count = 0
@@ -1,4 +1,4 @@
1
1
  module MailRoom
2
2
  # Current version of gitlab-mail_room gem
3
- VERSION = "0.0.14"
3
+ VERSION = "0.0.18"
4
4
  end
data/mail_room.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
19
19
 
20
20
  gem.add_dependency "net-imap", ">= 0.2.1"
21
21
  gem.add_dependency "oauth2", "~> 1.4.4"
22
+ gem.add_dependency "jwt", ">= 2.0"
22
23
 
23
24
  # Pinning io-wait to 0.1.0, which is the last version to support Ruby < 3
24
25
  gem.add_dependency "io-wait", "~> 0.1.0"
@@ -34,7 +35,7 @@ Gem::Specification.new do |gem|
34
35
  gem.add_development_dependency "faraday"
35
36
  gem.add_development_dependency "mail"
36
37
  gem.add_development_dependency "letter_opener"
37
- gem.add_development_dependency "redis", "~> 3.3.1"
38
+ gem.add_development_dependency "redis", "~> 4"
38
39
  gem.add_development_dependency "redis-namespace"
39
40
  gem.add_development_dependency "pg"
40
41
  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
@@ -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
@@ -4,6 +4,7 @@ require 'mail_room/delivery/sidekiq'
4
4
  describe MailRoom::Delivery::Sidekiq do
5
5
  subject { described_class.new(options) }
6
6
  let(:redis) { subject.send(:client) }
7
+ let(:raw_client) { redis._client }
7
8
  let(:options) { MailRoom::Delivery::Sidekiq::Options.new(mailbox) }
8
9
 
9
10
  describe '#options' do
@@ -20,7 +21,7 @@ describe MailRoom::Delivery::Sidekiq do
20
21
 
21
22
  context 'with simple redis url' do
22
23
  it 'client has same specified redis_url' do
23
- expect(redis.client.options[:url]).to eq(redis_url)
24
+ expect(raw_client.options[:url]).to eq(redis_url)
24
25
  end
25
26
 
26
27
  it 'client is a instance of RedisNamespace class' do
@@ -39,7 +40,7 @@ describe MailRoom::Delivery::Sidekiq do
39
40
  end
40
41
 
41
42
  it 'client has correct redis_url' do
42
- expect(redis.client.options[:url]).to eq(redis_url)
43
+ expect(raw_client.options[:url]).to eq(redis_url)
43
44
  end
44
45
 
45
46
 
@@ -87,10 +88,10 @@ describe MailRoom::Delivery::Sidekiq do
87
88
  before { ::Redis::Client::Connector::Sentinel.any_instance.stubs(:resolve).returns(sentinels) }
88
89
 
89
90
  it 'client has same specified sentinel params' do
90
- expect(redis.client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
91
- expect(redis.client.options[:host]).to eq('sentinel-master')
92
- expect(redis.client.options[:password]).to eq('mypassword')
93
- expect(redis.client.options[:sentinels]).to eq(sentinels)
91
+ expect(raw_client.instance_variable_get(:@connector)).to be_a Redis::Client::Connector::Sentinel
92
+ expect(raw_client.options[:host]).to eq('sentinel-master')
93
+ expect(raw_client.options[:password]).to eq('mypassword')
94
+ expect(raw_client.options[:sentinels]).to eq(sentinels)
94
95
  end
95
96
  end
96
97
 
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ require 'mail_room/jwt'
4
+
5
+ describe MailRoom::JWT do
6
+ let(:secret_path) { File.expand_path('../fixtures/jwt_secret', File.dirname(__FILE__)) }
7
+ let(:secret) { Base64.strict_decode64(File.read(secret_path).chomp) }
8
+
9
+ let(:standard_config) do
10
+ {
11
+ secret_path: secret_path,
12
+ issuer: 'mailroom',
13
+ header: 'Mailroom-Api-Request',
14
+ algorithm: 'HS256'
15
+ }
16
+ end
17
+
18
+ describe '#token' do
19
+ let(:jwt) { described_class.new(**standard_config) }
20
+
21
+ it 'generates a valid jwt token' do
22
+ token = jwt.token
23
+ expect(token).not_to be_empty
24
+
25
+ payload = nil
26
+ expect do
27
+ payload = JWT.decode(token, secret, true, iss: 'mailroom', verify_iat: true, verify_iss: true, algorithm: 'HS256')
28
+ end.not_to raise_error
29
+ expect(payload).to be_an(Array)
30
+ expect(payload).to match(
31
+ [
32
+ a_hash_including(
33
+ 'iss' => 'mailroom',
34
+ 'nonce' => be_a(String),
35
+ 'iat' => be_a(Integer)
36
+ ),
37
+ { 'alg' => 'HS256' }
38
+ ]
39
+ )
40
+ end
41
+
42
+ it 'generates a different token for each invocation' do
43
+ expect(jwt.token).not_to eql(jwt.token)
44
+ end
45
+ end
46
+
47
+ describe '#valid?' do
48
+ it 'returns true if all essential components are present' do
49
+ jwt = described_class.new(**standard_config)
50
+ expect(jwt.valid?).to eql(true)
51
+ end
52
+
53
+ it 'returns true if header and secret path are present' do
54
+ jwt = described_class.new(
55
+ secret_path: secret_path,
56
+ header: 'Mailroom-Api-Request',
57
+ issuer: nil,
58
+ algorithm: nil
59
+ )
60
+ expect(jwt.valid?).to eql(true)
61
+ expect(jwt.issuer).to eql(described_class::DEFAULT_ISSUER)
62
+ expect(jwt.algorithm).to eql(described_class::DEFAULT_ALGORITHM)
63
+ end
64
+
65
+ it 'returns false if either header or secret_path are missing' do
66
+ expect(described_class.new(
67
+ secret_path: nil,
68
+ header: 'Mailroom-Api-Request',
69
+ issuer: nil,
70
+ algorithm: nil
71
+ ).valid?).to eql(false)
72
+ expect(described_class.new(
73
+ secret_path: secret_path,
74
+ header: nil,
75
+ issuer: nil,
76
+ algorithm: nil
77
+ ).valid?).to eql(false)
78
+ end
79
+ end
80
+ end
@@ -17,34 +17,53 @@ describe MailRoom::MicrosoftGraph::Connection do
17
17
  let(:base_url) { 'https://graph.microsoft.com/v1.0/users/user@example.com/mailFolders/inbox/messages' }
18
18
  let(:message_base_url) { 'https://graph.microsoft.com/v1.0/users/user@example.com/messages' }
19
19
 
20
+ let(:connection) { described_class.new(mailbox) }
21
+ let(:uid) { 1 }
22
+ let(:access_token) { SecureRandom.hex }
23
+ let(:refresh_token) { SecureRandom.hex }
24
+ let(:expires_in) { Time.now + 3600 }
25
+ let(:unread_messages_body) { '' }
26
+ let(:status) { 200 }
27
+ let!(:stub_token) do
28
+ stub_request(:post, "https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token").to_return(
29
+ body: { 'access_token' => access_token, 'refresh_token' => refresh_token, 'expires_in' => expires_in }.to_json,
30
+ headers: { 'Content-Type' => 'application/json' }
31
+ )
32
+ end
33
+ let!(:stub_unread_messages_request) do
34
+ stub_request(:get, "#{base_url}?$filter=isRead%20eq%20false").to_return(
35
+ status: status,
36
+ body: unread_messages_body.to_json,
37
+ headers: { 'Content-Type' => 'application/json' }
38
+ )
39
+ end
40
+
20
41
  before do
21
42
  WebMock.enable!
22
43
  end
23
44
 
24
- context '#wait' do
25
- let(:connection) { described_class.new(mailbox) }
26
- let(:uid) { 1 }
27
- let(:access_token) { SecureRandom.hex }
28
- let(:refresh_token) { SecureRandom.hex }
29
- let(:expires_in) { Time.now + 3600 }
30
- let(:unread_messages_body) { '' }
31
- let(:status) { 200 }
32
- let!(:stub_token) do
33
- stub_request(:post, "https://login.microsoftonline.com/#{tenant_id}/oauth2/v2.0/token").to_return(
34
- body: { 'access_token' => access_token, 'refresh_token' => refresh_token, 'expires_in' => expires_in }.to_json,
35
- headers: { 'Content-Type' => 'application/json' }
36
- )
45
+ context '#quit' do
46
+ it 'returns false' do
47
+ expect(connection.stopped?).to be_falsey
37
48
  end
38
- let!(:stub_unread_messages_request) do
39
- stub_request(:get, "#{base_url}?$filter=isRead%20eq%20false").to_return(
40
- status: status,
41
- body: unread_messages_body.to_json,
42
- headers: { 'Content-Type' => 'application/json' }
43
- )
49
+
50
+ it 'returns true' do
51
+ connection.quit
52
+
53
+ expect(connection.stopped?).to be_truthy
54
+ end
55
+
56
+ it 'does not attempt to process the mailbox' do
57
+ connection.quit
58
+
59
+ connection.expects(:process_mailbox).times(0)
60
+ connection.wait
44
61
  end
62
+ end
45
63
 
64
+ context '#wait' do
46
65
  before do
47
- connection.stubs(:wait_for_new_messages)
66
+ connection.stubs(:do_sleep)
48
67
  end
49
68
 
50
69
  describe 'poll interval' do
@@ -52,6 +71,12 @@ describe MailRoom::MicrosoftGraph::Connection do
52
71
  expect(connection.send(:poll_interval)).to eq(60)
53
72
  end
54
73
 
74
+ it 'calls do_sleep 60 times' do
75
+ connection.expects(:do_sleep).with(1).times(60)
76
+
77
+ connection.wait
78
+ end
79
+
55
80
  context 'interval set to 10' do
56
81
  let(:options) do
57
82
  {
@@ -68,6 +93,12 @@ describe MailRoom::MicrosoftGraph::Connection do
68
93
  it 'sets the poll interval to 10' do
69
94
  expect(connection.send(:poll_interval)).to eq(10)
70
95
  end
96
+
97
+ it 'calls do_sleep 10 times' do
98
+ connection.expects(:do_sleep).with(1).times(10)
99
+
100
+ connection.wait
101
+ end
71
102
  end
72
103
  end
73
104
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-mail_room
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Pitale
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-21 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-imap
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.4.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: jwt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: io-wait
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -184,14 +198,14 @@ dependencies:
184
198
  requirements:
185
199
  - - "~>"
186
200
  - !ruby/object:Gem::Version
187
- version: 3.3.1
201
+ version: '4'
188
202
  type: :development
189
203
  prerelease: false
190
204
  version_requirements: !ruby/object:Gem::Requirement
191
205
  requirements:
192
206
  - - "~>"
193
207
  - !ruby/object:Gem::Version
194
- version: 3.3.1
208
+ version: '4'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: redis-namespace
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -265,6 +279,7 @@ files:
265
279
  - ".travis.yml"
266
280
  - CHANGELOG.md
267
281
  - CODE_OF_CONDUCT.md
282
+ - CONTRIBUTING.md
268
283
  - Gemfile
269
284
  - LICENSE.txt
270
285
  - README.md
@@ -290,6 +305,7 @@ files:
290
305
  - lib/mail_room/imap.rb
291
306
  - lib/mail_room/imap/connection.rb
292
307
  - lib/mail_room/imap/message.rb
308
+ - lib/mail_room/jwt.rb
293
309
  - lib/mail_room/logger/structured.rb
294
310
  - lib/mail_room/mailbox.rb
295
311
  - lib/mail_room/mailbox_watcher.rb
@@ -299,6 +315,7 @@ files:
299
315
  - lib/mail_room/version.rb
300
316
  - logfile.log
301
317
  - mail_room.gemspec
318
+ - spec/fixtures/jwt_secret
302
319
  - spec/fixtures/test_config.yml
303
320
  - spec/lib/arbitration/redis_spec.rb
304
321
  - spec/lib/cli_spec.rb
@@ -313,6 +330,7 @@ files:
313
330
  - spec/lib/health_check_spec.rb
314
331
  - spec/lib/imap/connection_spec.rb
315
332
  - spec/lib/imap/message_spec.rb
333
+ - spec/lib/jwt_spec.rb
316
334
  - spec/lib/logger/structured_spec.rb
317
335
  - spec/lib/mailbox_spec.rb
318
336
  - spec/lib/mailbox_watcher_spec.rb
@@ -322,7 +340,7 @@ files:
322
340
  homepage: http://github.com/tpitale/mail_room
323
341
  licenses: []
324
342
  metadata: {}
325
- post_install_message:
343
+ post_install_message:
326
344
  rdoc_options: []
327
345
  require_paths:
328
346
  - lib
@@ -337,12 +355,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
337
355
  - !ruby/object:Gem::Version
338
356
  version: '0'
339
357
  requirements: []
340
- rubygems_version: 3.1.4
341
- signing_key:
358
+ rubygems_version: 3.1.6
359
+ signing_key:
342
360
  specification_version: 4
343
361
  summary: mail_room will proxy email (gmail) from IMAP to a callback URL, logger, or
344
362
  letter_opener
345
363
  test_files:
364
+ - spec/fixtures/jwt_secret
346
365
  - spec/fixtures/test_config.yml
347
366
  - spec/lib/arbitration/redis_spec.rb
348
367
  - spec/lib/cli_spec.rb
@@ -357,6 +376,7 @@ test_files:
357
376
  - spec/lib/health_check_spec.rb
358
377
  - spec/lib/imap/connection_spec.rb
359
378
  - spec/lib/imap/message_spec.rb
379
+ - spec/lib/jwt_spec.rb
360
380
  - spec/lib/logger/structured_spec.rb
361
381
  - spec/lib/mailbox_spec.rb
362
382
  - spec/lib/mailbox_watcher_spec.rb