active_elastic_job 1.4.0 → 1.4.1
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 +4 -4
- data/lib/active_elastic_job/md5_message_digest_calculation.rb +17 -24
- data/lib/active_elastic_job/message_verifier.rb +9 -7
- data/lib/active_elastic_job/rack/sqs_message_consumer.rb +14 -5
- data/lib/active_elastic_job/version.rb +1 -1
- data/lib/active_job/queue_adapters/active_elastic_job_adapter.rb +27 -23
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7f80373d7f57286083c91bfb62632d463df9b7a
|
4
|
+
data.tar.gz: 30ad4c79acf1d9a8393092bdf430f7416b606239
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72d3f884abb6f6b16d0c43fe2c537ba64d80acba7e65ff2a97faaea99d16b4e6b45666aeb33f232b95cf227b8d16af172385bc9dfcc5d978720fe97f3ea6742a
|
7
|
+
data.tar.gz: b5f4204e84cc39de88f67f321fbc758021b1fbcbb698cc7c991e1a1e0e14b0b9d6d177f92f92191840a01e9e72e29e4b5796886dfa4d2482e310889b89eafda1
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'openssl'
|
2
2
|
module ActiveElasticJob
|
3
3
|
# This module provides methods that calculate the MD5 digest for Amazon
|
4
4
|
# SQS message bodies and message attributes.
|
@@ -29,35 +29,30 @@ module ActiveElasticJob
|
|
29
29
|
'Number' => 1
|
30
30
|
}
|
31
31
|
|
32
|
-
|
32
|
+
NORMALIZED_ENCODING = Encoding::UTF_8
|
33
33
|
|
34
|
-
# Returns MD5 digest of +message_body+.
|
35
34
|
def md5_of_message_body(message_body)
|
36
35
|
OpenSSL::Digest::MD5.hexdigest(message_body)
|
37
36
|
end
|
38
37
|
|
39
|
-
# Returns MD5 digest of +message_attributes+.
|
40
|
-
#
|
41
|
-
# The calculation follows the official algorithm which
|
42
|
-
# is specified by Amazon.
|
43
38
|
def md5_of_message_attributes(message_attributes)
|
44
|
-
encoded =
|
45
|
-
|
46
|
-
|
39
|
+
encoded = { }
|
40
|
+
message_attributes.each do |name, attribute|
|
41
|
+
name = name.to_s
|
42
|
+
encoded[name] = String.new
|
43
|
+
encoded[name] << encode_length_and_bytes(name) <<
|
44
|
+
encode_length_and_bytes(attribute[:data_type]) <<
|
45
|
+
[TRANSPORT_TYPE_ENCODINGS[attribute[:data_type]]].pack('C'.freeze)
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if string_value = v['string_value'] || v[:string_value]
|
53
|
-
hash[name.to_s] << encode_length_and_string(string_value)
|
54
|
-
elsif binary_value = v['binary_value'] || v[:binary_value]
|
55
|
-
hash[name.to_s] << encode_length_and_bytes(binary_value)
|
47
|
+
if string_value = attribute[:string_value]
|
48
|
+
encoded[name] << encode_length_and_string(string_value)
|
49
|
+
elsif binary_value = attribute[:binary_value]
|
50
|
+
encoded[name] << encode_length_and_bytes(binary_value)
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
59
|
-
buffer = encoded.keys.sort.reduce(
|
60
|
-
|
54
|
+
buffer = encoded.keys.sort.reduce(String.new) do |string, name|
|
55
|
+
string << encoded[name]
|
61
56
|
end
|
62
57
|
OpenSSL::Digest::MD5.hexdigest(buffer)
|
63
58
|
end
|
@@ -65,15 +60,13 @@ module ActiveElasticJob
|
|
65
60
|
private
|
66
61
|
|
67
62
|
def encode_length_and_string(string)
|
68
|
-
return '' if string.nil?
|
69
63
|
string = String.new(string)
|
70
|
-
string.encode!(
|
64
|
+
string.encode!(NORMALIZED_ENCODING)
|
71
65
|
encode_length_and_bytes(string)
|
72
66
|
end
|
73
67
|
|
74
68
|
def encode_length_and_bytes(bytes)
|
75
|
-
|
76
|
-
[ bytes.bytesize, bytes ].pack("L>a#{bytes.bytesize}")
|
69
|
+
[bytes.bytesize, bytes].pack('L>a*'.freeze)
|
77
70
|
end
|
78
71
|
end
|
79
72
|
end
|
@@ -13,20 +13,22 @@ module ActiveElasticJob
|
|
13
13
|
@secret = secret
|
14
14
|
end
|
15
15
|
|
16
|
-
def verify
|
16
|
+
def verify(message, digest)
|
17
17
|
if message.nil? || message.blank? || digest.nil? || digest.blank?
|
18
|
-
|
18
|
+
return false
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
return ActiveSupport::SecurityUtils.secure_compare(
|
22
|
+
digest, generate_digest(message))
|
23
|
+
end
|
24
|
+
|
25
|
+
def verify!(message, digest)
|
26
|
+
raise InvalidDigest unless verify(message, digest)
|
25
27
|
end
|
26
28
|
|
27
29
|
def generate_digest(message)
|
28
30
|
require 'openssl' unless defined?(OpenSSL)
|
29
|
-
OpenSSL::HMAC.hexdigest(OpenSSL::Digest
|
31
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, message)
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
@@ -5,8 +5,8 @@ module ActiveElasticJob
|
|
5
5
|
# This middleware intercepts requests which are sent by the SQS daemon
|
6
6
|
# running in {Amazon Elastic Beanstalk worker environments}[http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html].
|
7
7
|
# It does this by looking at the +User-Agent+ header.
|
8
|
-
# Furthermore, it verifies the digest which is sent along with a legit SQS
|
9
|
-
# and passed as an HTTP header in the resulting request.
|
8
|
+
# Furthermore, it verifies the digest which is sent along with a legit SQS
|
9
|
+
# message, and passed as an HTTP header in the resulting request.
|
10
10
|
# The digest is based on Rails' +secrets.secret_key_base+.
|
11
11
|
# Therefore, the application running in the web environment, which generates
|
12
12
|
# the digest, and the application running in the worker
|
@@ -36,11 +36,20 @@ module ActiveElasticJob
|
|
36
36
|
job = JSON.load(request.body)
|
37
37
|
ActiveJob::Base.execute(job)
|
38
38
|
rescue ActiveElasticJob::MessageVerifier::InvalidDigest => e
|
39
|
-
return [
|
39
|
+
return [
|
40
|
+
'403',
|
41
|
+
{CONTENT_TYPE_HEADER_NAME => 'text/plain' },
|
42
|
+
["incorrect digest"]]
|
40
43
|
rescue StandardError => e
|
41
|
-
return [
|
44
|
+
return [
|
45
|
+
'500',
|
46
|
+
{CONTENT_TYPE_HEADER_NAME => 'text/plain' },
|
47
|
+
[e.message]]
|
42
48
|
end
|
43
|
-
return [
|
49
|
+
return [
|
50
|
+
OK_RESPONSE_CODE ,
|
51
|
+
{CONTENT_TYPE_HEADER_NAME => CONTENT_TYPE },
|
52
|
+
[ '' ]]
|
44
53
|
end
|
45
54
|
@app.call(env)
|
46
55
|
end
|
@@ -8,9 +8,11 @@ module ActiveJob
|
|
8
8
|
# environments}[http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html].
|
9
9
|
#
|
10
10
|
# This adapter serializes job objects and sends them as a message to an
|
11
|
-
# Amazon SQS queue specified by the job's queue name,
|
11
|
+
# Amazon SQS queue specified by the job's queue name,
|
12
|
+
# see <tt>ActiveJob::Base.queue_as</tt>
|
12
13
|
#
|
13
|
-
# To use Active Elastic Job, set the queue_adapter config
|
14
|
+
# To use Active Elastic Job, set the queue_adapter config
|
15
|
+
# to +:active_elastic_job+.
|
14
16
|
#
|
15
17
|
# Rails.application.config.active_job.queue_adapter = :active_elastic_job
|
16
18
|
class ActiveElasticJobAdapter
|
@@ -34,9 +36,9 @@ which exceeds the allowed maximum of #{MAX_MESSAGE_SIZE} bytes imposed by Amazon
|
|
34
36
|
end
|
35
37
|
|
36
38
|
# Raised when job queue does not exist. The job queue is determined by
|
37
|
-
# <tt>ActiveJob::Base.queue_as</tt>. You can either: (1) create a new
|
38
|
-
# SQS queue and attach a worker environment to it, or (2) select a
|
39
|
-
# queue for your jobs.
|
39
|
+
# <tt>ActiveJob::Base.queue_as</tt>. You can either: (1) create a new
|
40
|
+
# Amazon SQS queue and attach a worker environment to it, or (2) select a
|
41
|
+
# different queue for your jobs.
|
40
42
|
#
|
41
43
|
# Example:
|
42
44
|
# * Open your AWS console and create an SQS queue named +high_priority+ in
|
@@ -49,12 +51,12 @@ which exceeds the allowed maximum of #{MAX_MESSAGE_SIZE} bytes imposed by Amazon
|
|
49
51
|
# end
|
50
52
|
class NonExistentQueue < Error
|
51
53
|
def initialize(queue_name)
|
52
|
-
msg =
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
msg = "The job is bound to queue at #{queue_name}. " <<
|
55
|
+
"Unfortunately a queue with this name does not exist in this " <<
|
56
|
+
"region. Either create an Amazon SQS queue named #{queue_name} - " <<
|
57
|
+
"you can do this in AWS console, make sure to select region " <<
|
58
|
+
"'#{ENV['AWS_REGION']}' - or you select another queue for your jobs."
|
59
|
+
|
58
60
|
super msg
|
59
61
|
end
|
60
62
|
end
|
@@ -62,11 +64,12 @@ region '#{ENV['AWS_REGION']}' - or you select another queue for your jobs.
|
|
62
64
|
# Raised when calculated MD5 digest does not match the MD5 Digest
|
63
65
|
# of the response from Amazon SQS.
|
64
66
|
class MD5MismatchError < Error
|
65
|
-
def initialize(
|
66
|
-
msg =
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
def initialize(message_id)
|
68
|
+
msg = "MD5 returned by Amazon SQS does not match the calculation " <<
|
69
|
+
"on the original request. The message with Message ID " <<
|
70
|
+
"#{message_id} sent to SQS might be corrupted."
|
71
|
+
|
72
|
+
super msg
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
@@ -128,13 +131,14 @@ The message with Message ID #{message_id} sent to SQS might be corrupted.
|
|
128
131
|
def calculate_delay(timestamp)
|
129
132
|
delay = (timestamp - Time.current.to_f).to_i + 1
|
130
133
|
if delay > MAX_DELAY_IN_MINUTES.minutes
|
131
|
-
msg
|
132
|
-
|
133
|
-
See http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
|
134
|
-
for further details!
|
135
|
-
|
136
|
-
raise RangeError
|
134
|
+
msg = "Jobs cannot be scheduled more than " <<
|
135
|
+
"#{MAX_DELAY_IN_MINUTES} minutes into the future. " <<
|
136
|
+
"See http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html" <<
|
137
|
+
" for further details!"
|
138
|
+
|
139
|
+
raise RangeError, msg
|
137
140
|
end
|
141
|
+
delay = 0 if delay < 0
|
138
142
|
delay
|
139
143
|
end
|
140
144
|
|
@@ -158,7 +162,7 @@ for further details!
|
|
158
162
|
@verifier.generate_digest(messsage_body)
|
159
163
|
end
|
160
164
|
|
161
|
-
def verify_md5_digests!(response, messsage_body, message_attributes
|
165
|
+
def verify_md5_digests!(response, messsage_body, message_attributes)
|
162
166
|
if md5_of_message_body(messsage_body) != response.md5_of_message_body
|
163
167
|
raise MD5MismatchError, response.message_id
|
164
168
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_elastic_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tawan Sierek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|