sidekiq 6.5.8 → 7.3.10
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/Changes.md +359 -15
- data/README.md +43 -35
- data/bin/multi_queue_bench +271 -0
- data/bin/sidekiq +3 -8
- data/bin/sidekiqload +213 -118
- data/bin/sidekiqmon +3 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +75 -0
- data/lib/generators/sidekiq/job_generator.rb +2 -0
- data/lib/sidekiq/api.rb +243 -162
- data/lib/sidekiq/capsule.rb +132 -0
- data/lib/sidekiq/cli.rb +61 -75
- data/lib/sidekiq/client.rb +88 -39
- data/lib/sidekiq/component.rb +26 -1
- data/lib/sidekiq/config.rb +311 -0
- data/lib/sidekiq/deploy.rb +64 -0
- data/lib/sidekiq/embedded.rb +63 -0
- data/lib/sidekiq/fetch.rb +12 -14
- data/lib/sidekiq/iterable_job.rb +55 -0
- data/lib/sidekiq/job/interrupt_handler.rb +24 -0
- data/lib/sidekiq/job/iterable/active_record_enumerator.rb +53 -0
- data/lib/sidekiq/job/iterable/csv_enumerator.rb +47 -0
- data/lib/sidekiq/job/iterable/enumerators.rb +135 -0
- data/lib/sidekiq/job/iterable.rb +294 -0
- data/lib/sidekiq/job.rb +382 -10
- data/lib/sidekiq/job_logger.rb +8 -7
- data/lib/sidekiq/job_retry.rb +42 -19
- data/lib/sidekiq/job_util.rb +53 -15
- data/lib/sidekiq/launcher.rb +71 -65
- data/lib/sidekiq/logger.rb +2 -27
- data/lib/sidekiq/manager.rb +9 -11
- data/lib/sidekiq/metrics/query.rb +10 -5
- data/lib/sidekiq/metrics/shared.rb +21 -9
- data/lib/sidekiq/metrics/tracking.rb +40 -26
- data/lib/sidekiq/middleware/chain.rb +19 -18
- data/lib/sidekiq/middleware/current_attributes.rb +85 -20
- data/lib/sidekiq/middleware/i18n.rb +2 -0
- data/lib/sidekiq/middleware/modules.rb +2 -0
- data/lib/sidekiq/monitor.rb +19 -5
- data/lib/sidekiq/paginator.rb +10 -4
- data/lib/sidekiq/processor.rb +62 -57
- data/lib/sidekiq/rails.rb +32 -16
- data/lib/sidekiq/redis_client_adapter.rb +31 -71
- data/lib/sidekiq/redis_connection.rb +54 -114
- data/lib/sidekiq/ring_buffer.rb +3 -0
- data/lib/sidekiq/scheduled.rb +22 -23
- data/lib/sidekiq/systemd.rb +2 -0
- data/lib/sidekiq/testing.rb +37 -46
- data/lib/sidekiq/transaction_aware_client.rb +23 -9
- data/lib/sidekiq/version.rb +6 -1
- data/lib/sidekiq/web/action.rb +29 -7
- data/lib/sidekiq/web/application.rb +84 -30
- data/lib/sidekiq/web/csrf_protection.rb +10 -7
- data/lib/sidekiq/web/helpers.rb +113 -52
- data/lib/sidekiq/web/router.rb +5 -2
- data/lib/sidekiq/web.rb +70 -17
- data/lib/sidekiq/worker_compatibility_alias.rb +13 -0
- data/lib/sidekiq.rb +78 -274
- data/sidekiq.gemspec +13 -10
- data/web/assets/javascripts/application.js +45 -0
- data/web/assets/javascripts/base-charts.js +106 -0
- data/web/assets/javascripts/dashboard-charts.js +194 -0
- data/web/assets/javascripts/dashboard.js +17 -233
- data/web/assets/javascripts/metrics.js +151 -115
- data/web/assets/stylesheets/application-dark.css +4 -0
- data/web/assets/stylesheets/application-rtl.css +10 -89
- data/web/assets/stylesheets/application.css +56 -296
- data/web/locales/ar.yml +70 -70
- data/web/locales/cs.yml +62 -62
- data/web/locales/da.yml +60 -53
- data/web/locales/de.yml +65 -65
- data/web/locales/el.yml +2 -7
- data/web/locales/en.yml +81 -71
- data/web/locales/es.yml +68 -68
- data/web/locales/fa.yml +65 -65
- data/web/locales/fr.yml +80 -67
- data/web/locales/gd.yml +98 -0
- data/web/locales/he.yml +65 -64
- data/web/locales/hi.yml +59 -59
- data/web/locales/it.yml +85 -54
- data/web/locales/ja.yml +67 -70
- data/web/locales/ko.yml +52 -52
- data/web/locales/lt.yml +66 -66
- data/web/locales/nb.yml +61 -61
- data/web/locales/nl.yml +52 -52
- data/web/locales/pl.yml +45 -45
- data/web/locales/pt-br.yml +78 -69
- data/web/locales/pt.yml +51 -51
- data/web/locales/ru.yml +67 -66
- data/web/locales/sv.yml +53 -53
- data/web/locales/ta.yml +60 -60
- data/web/locales/tr.yml +100 -0
- data/web/locales/uk.yml +85 -61
- data/web/locales/ur.yml +64 -64
- data/web/locales/vi.yml +67 -67
- data/web/locales/zh-cn.yml +20 -19
- data/web/locales/zh-tw.yml +10 -2
- data/web/views/_footer.erb +16 -2
- data/web/views/_job_info.erb +18 -2
- data/web/views/_metrics_period_select.erb +12 -0
- data/web/views/_paging.erb +2 -0
- data/web/views/_poll_link.erb +1 -1
- data/web/views/_summary.erb +7 -7
- data/web/views/busy.erb +46 -35
- data/web/views/dashboard.erb +32 -8
- data/web/views/filtering.erb +6 -0
- data/web/views/layout.erb +6 -6
- data/web/views/metrics.erb +47 -26
- data/web/views/metrics_for_job.erb +43 -71
- data/web/views/morgue.erb +7 -11
- data/web/views/queue.erb +11 -15
- data/web/views/queues.erb +9 -3
- data/web/views/retries.erb +5 -9
- data/web/views/scheduled.erb +12 -13
- metadata +81 -38
- data/lib/sidekiq/delay.rb +0 -43
- data/lib/sidekiq/extensions/action_mailer.rb +0 -48
- data/lib/sidekiq/extensions/active_record.rb +0 -43
- data/lib/sidekiq/extensions/class_methods.rb +0 -43
- data/lib/sidekiq/extensions/generic_proxy.rb +0 -33
- data/lib/sidekiq/metrics/deploy.rb +0 -47
- data/lib/sidekiq/worker.rb +0 -370
- data/web/assets/javascripts/graph.js +0 -16
- /data/{LICENSE → LICENSE.txt} +0 -0
|
@@ -5,15 +5,28 @@ require "sidekiq/client"
|
|
|
5
5
|
|
|
6
6
|
module Sidekiq
|
|
7
7
|
class TransactionAwareClient
|
|
8
|
-
def initialize(
|
|
9
|
-
@redis_client = Client.new(
|
|
8
|
+
def initialize(pool: nil, config: nil)
|
|
9
|
+
@redis_client = Client.new(pool: pool, config: config)
|
|
10
|
+
@transaction_backend =
|
|
11
|
+
if ActiveRecord.version >= Gem::Version.new("7.2")
|
|
12
|
+
ActiveRecord.method(:after_all_transactions_commit)
|
|
13
|
+
else
|
|
14
|
+
AfterCommitEverywhere.method(:after_commit)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def batching?
|
|
19
|
+
Thread.current[:sidekiq_batch]
|
|
10
20
|
end
|
|
11
21
|
|
|
12
22
|
def push(item)
|
|
23
|
+
# 6160 we can't support both Sidekiq::Batch and transactions.
|
|
24
|
+
return @redis_client.push(item) if batching?
|
|
25
|
+
|
|
13
26
|
# pre-allocate the JID so we can return it immediately and
|
|
14
27
|
# save it to the database as part of the transaction.
|
|
15
28
|
item["jid"] ||= SecureRandom.hex(12)
|
|
16
|
-
|
|
29
|
+
@transaction_backend.call { @redis_client.push(item) }
|
|
17
30
|
item["jid"]
|
|
18
31
|
end
|
|
19
32
|
|
|
@@ -31,14 +44,15 @@ end
|
|
|
31
44
|
# Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer
|
|
32
45
|
module Sidekiq
|
|
33
46
|
def self.transactional_push!
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
if ActiveRecord.version < Gem::Version.new("7.2")
|
|
48
|
+
begin
|
|
49
|
+
require "after_commit_everywhere"
|
|
50
|
+
rescue LoadError
|
|
51
|
+
raise %q(You need ActiveRecord >= 7.2 or to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client)
|
|
52
|
+
end
|
|
39
53
|
end
|
|
40
54
|
|
|
41
|
-
default_job_options["client_class"] = Sidekiq::TransactionAwareClient
|
|
55
|
+
Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient
|
|
42
56
|
Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class"
|
|
43
57
|
true
|
|
44
58
|
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
|
@@ -15,13 +15,19 @@ module Sidekiq
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def halt(res)
|
|
18
|
-
throw :halt, [res, {
|
|
18
|
+
throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]]
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def redirect(location)
|
|
22
|
-
throw :halt, [302, {
|
|
22
|
+
throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []]
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def reload_page
|
|
26
|
+
current_location = request.referer.gsub(request.base_url, "")
|
|
27
|
+
redirect current_location
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# deprecated, will warn in 8.0
|
|
25
31
|
def params
|
|
26
32
|
indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key }
|
|
27
33
|
|
|
@@ -31,8 +37,19 @@ module Sidekiq
|
|
|
31
37
|
indifferent_hash
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
# Use like `url_params("page")` within your action blocks
|
|
41
|
+
def url_params(key)
|
|
42
|
+
request.params[key]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Use like `route_params(:name)` within your action blocks
|
|
46
|
+
# key is required in 8.0, nil is only used for backwards compatibility
|
|
47
|
+
def route_params(key = nil)
|
|
48
|
+
if key
|
|
49
|
+
env[WebRouter::ROUTE_PARAMS][key]
|
|
50
|
+
else
|
|
51
|
+
env[WebRouter::ROUTE_PARAMS]
|
|
52
|
+
end
|
|
36
53
|
end
|
|
37
54
|
|
|
38
55
|
def session
|
|
@@ -42,8 +59,13 @@ module Sidekiq
|
|
|
42
59
|
def erb(content, options = {})
|
|
43
60
|
if content.is_a? Symbol
|
|
44
61
|
unless respond_to?(:"_erb_#{content}")
|
|
45
|
-
|
|
46
|
-
|
|
62
|
+
views = options[:views] || Web.settings.views
|
|
63
|
+
filename = "#{views}/#{content}.erb"
|
|
64
|
+
src = ERB.new(File.read(filename)).src
|
|
65
|
+
|
|
66
|
+
# Need to use lineno less by 1 because erb generates a
|
|
67
|
+
# comment before the source code.
|
|
68
|
+
WebAction.class_eval <<-RUBY, filename, -1 # standard:disable Style/EvalWithLocation
|
|
47
69
|
def _erb_#{content}
|
|
48
70
|
#{src}
|
|
49
71
|
end
|
|
@@ -68,7 +90,7 @@ module Sidekiq
|
|
|
68
90
|
end
|
|
69
91
|
|
|
70
92
|
def json(payload)
|
|
71
|
-
[200, {
|
|
93
|
+
[200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]]
|
|
72
94
|
end
|
|
73
95
|
|
|
74
96
|
def initialize(env, block)
|
|
@@ -5,7 +5,7 @@ module Sidekiq
|
|
|
5
5
|
extend WebRouter
|
|
6
6
|
|
|
7
7
|
REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human]
|
|
8
|
-
|
|
8
|
+
CSP_HEADER_TEMPLATE = [
|
|
9
9
|
"default-src 'self' https: http:",
|
|
10
10
|
"child-src 'self'",
|
|
11
11
|
"connect-src 'self' https: http: wss: ws:",
|
|
@@ -15,11 +15,17 @@ module Sidekiq
|
|
|
15
15
|
"manifest-src 'self'",
|
|
16
16
|
"media-src 'self'",
|
|
17
17
|
"object-src 'none'",
|
|
18
|
-
"script-src 'self'
|
|
19
|
-
"style-src 'self' https: http: 'unsafe-inline'",
|
|
18
|
+
"script-src 'self' 'nonce-!placeholder!'",
|
|
19
|
+
"style-src 'self' https: http: 'unsafe-inline'", # TODO Nonce in 8.0
|
|
20
20
|
"worker-src 'self'",
|
|
21
21
|
"base-uri 'self'"
|
|
22
22
|
].join("; ").freeze
|
|
23
|
+
METRICS_PERIODS = {
|
|
24
|
+
"1h" => 60,
|
|
25
|
+
"2h" => 120,
|
|
26
|
+
"4h" => 240,
|
|
27
|
+
"8h" => 480
|
|
28
|
+
}
|
|
23
29
|
|
|
24
30
|
def initialize(klass)
|
|
25
31
|
@klass = klass
|
|
@@ -43,13 +49,13 @@ module Sidekiq
|
|
|
43
49
|
|
|
44
50
|
head "/" do
|
|
45
51
|
# HEAD / is the cheapest heartbeat possible,
|
|
46
|
-
# it hits Redis to ensure connectivity
|
|
47
|
-
|
|
48
|
-
""
|
|
52
|
+
# it hits Redis to ensure connectivity and returns
|
|
53
|
+
# the size of the default queue
|
|
54
|
+
Sidekiq.redis { |c| c.llen("queue:default") }.to_s
|
|
49
55
|
end
|
|
50
56
|
|
|
51
57
|
get "/" do
|
|
52
|
-
@redis_info = redis_info.
|
|
58
|
+
@redis_info = redis_info.slice(*REDIS_KEYS)
|
|
53
59
|
days = (params["days"] || 30).to_i
|
|
54
60
|
return halt(401) if days < 1 || days > 180
|
|
55
61
|
|
|
@@ -61,15 +67,25 @@ module Sidekiq
|
|
|
61
67
|
end
|
|
62
68
|
|
|
63
69
|
get "/metrics" do
|
|
70
|
+
x = params[:substr]
|
|
71
|
+
class_filter = (x.nil? || x == "") ? nil : Regexp.new(Regexp.escape(x), Regexp::IGNORECASE)
|
|
72
|
+
|
|
64
73
|
q = Sidekiq::Metrics::Query.new
|
|
65
|
-
@
|
|
74
|
+
@period = h((params[:period] || "")[0..1])
|
|
75
|
+
@periods = METRICS_PERIODS
|
|
76
|
+
minutes = @periods.fetch(@period, @periods.values.first)
|
|
77
|
+
@query_result = q.top_jobs(minutes: minutes, class_filter: class_filter)
|
|
78
|
+
|
|
66
79
|
erb(:metrics)
|
|
67
80
|
end
|
|
68
81
|
|
|
69
82
|
get "/metrics/:name" do
|
|
70
83
|
@name = route_params[:name]
|
|
84
|
+
@period = h((params[:period] || "")[0..1])
|
|
71
85
|
q = Sidekiq::Metrics::Query.new
|
|
72
|
-
@
|
|
86
|
+
@periods = METRICS_PERIODS
|
|
87
|
+
minutes = @periods.fetch(@period, @periods.values.first)
|
|
88
|
+
@query_result = q.for_job(@name, minutes: minutes)
|
|
73
89
|
erb(:metrics_for_job)
|
|
74
90
|
end
|
|
75
91
|
|
|
@@ -82,11 +98,14 @@ module Sidekiq
|
|
|
82
98
|
|
|
83
99
|
post "/busy" do
|
|
84
100
|
if params["identity"]
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
101
|
+
pro = Sidekiq::ProcessSet[params["identity"]]
|
|
102
|
+
|
|
103
|
+
pro.quiet! if params["quiet"]
|
|
104
|
+
pro.stop! if params["stop"]
|
|
88
105
|
else
|
|
89
106
|
processes.each do |pro|
|
|
107
|
+
next if pro.embedded?
|
|
108
|
+
|
|
90
109
|
pro.quiet! if params["quiet"]
|
|
91
110
|
pro.stop! if params["stop"]
|
|
92
111
|
end
|
|
@@ -138,9 +157,15 @@ module Sidekiq
|
|
|
138
157
|
end
|
|
139
158
|
|
|
140
159
|
get "/morgue" do
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
160
|
+
x = params[:substr]
|
|
161
|
+
|
|
162
|
+
if x && x != ""
|
|
163
|
+
@dead = search(Sidekiq::DeadSet.new, x)
|
|
164
|
+
else
|
|
165
|
+
@count = (params["count"] || 25).to_i
|
|
166
|
+
(@current_page, @total_size, @dead) = page("dead", params["page"], @count, reverse: true)
|
|
167
|
+
@dead = @dead.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
|
168
|
+
end
|
|
144
169
|
|
|
145
170
|
erb(:morgue)
|
|
146
171
|
end
|
|
@@ -159,7 +184,7 @@ module Sidekiq
|
|
|
159
184
|
end
|
|
160
185
|
|
|
161
186
|
post "/morgue" do
|
|
162
|
-
redirect(request.path) unless
|
|
187
|
+
redirect(request.path) unless url_params("key")
|
|
163
188
|
|
|
164
189
|
params["key"].each do |key|
|
|
165
190
|
job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
|
|
@@ -182,7 +207,7 @@ module Sidekiq
|
|
|
182
207
|
end
|
|
183
208
|
|
|
184
209
|
post "/morgue/:key" do
|
|
185
|
-
key = route_params
|
|
210
|
+
key = route_params(:key)
|
|
186
211
|
halt(404) unless key
|
|
187
212
|
|
|
188
213
|
job = Sidekiq::DeadSet.new.fetch(*parse_params(key)).first
|
|
@@ -192,9 +217,15 @@ module Sidekiq
|
|
|
192
217
|
end
|
|
193
218
|
|
|
194
219
|
get "/retries" do
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
220
|
+
x = url_params("substr")
|
|
221
|
+
|
|
222
|
+
if x && x != ""
|
|
223
|
+
@retries = search(Sidekiq::RetrySet.new, x)
|
|
224
|
+
else
|
|
225
|
+
@count = (params["count"] || 25).to_i
|
|
226
|
+
(@current_page, @total_size, @retries) = page("retry", params["page"], @count)
|
|
227
|
+
@retries = @retries.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
|
228
|
+
end
|
|
198
229
|
|
|
199
230
|
erb(:retries)
|
|
200
231
|
end
|
|
@@ -247,9 +278,15 @@ module Sidekiq
|
|
|
247
278
|
end
|
|
248
279
|
|
|
249
280
|
get "/scheduled" do
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
281
|
+
x = params[:substr]
|
|
282
|
+
|
|
283
|
+
if x && x != ""
|
|
284
|
+
@scheduled = search(Sidekiq::ScheduledSet.new, x)
|
|
285
|
+
else
|
|
286
|
+
@count = (params["count"] || 25).to_i
|
|
287
|
+
(@current_page, @total_size, @scheduled) = page("schedule", params["page"], @count)
|
|
288
|
+
@scheduled = @scheduled.map { |msg, score| Sidekiq::SortedEntry.new(nil, score, msg) }
|
|
289
|
+
end
|
|
253
290
|
|
|
254
291
|
erb(:scheduled)
|
|
255
292
|
end
|
|
@@ -291,7 +328,7 @@ module Sidekiq
|
|
|
291
328
|
|
|
292
329
|
get "/stats" do
|
|
293
330
|
sidekiq_stats = Sidekiq::Stats.new
|
|
294
|
-
redis_stats = redis_info.
|
|
331
|
+
redis_stats = redis_info.slice(*REDIS_KEYS)
|
|
295
332
|
json(
|
|
296
333
|
sidekiq: {
|
|
297
334
|
processed: sidekiq_stats.processed,
|
|
@@ -310,12 +347,24 @@ module Sidekiq
|
|
|
310
347
|
end
|
|
311
348
|
|
|
312
349
|
get "/stats/queues" do
|
|
313
|
-
json Sidekiq::Stats
|
|
350
|
+
json Sidekiq::Stats.new.queues
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
post "/change_locale" do
|
|
354
|
+
locale = params["locale"]
|
|
355
|
+
|
|
356
|
+
match = available_locales.find { |available|
|
|
357
|
+
locale == available
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
session[:locale] = match if match
|
|
361
|
+
|
|
362
|
+
reload_page
|
|
314
363
|
end
|
|
315
364
|
|
|
316
365
|
def call(env)
|
|
317
366
|
action = self.class.match(env)
|
|
318
|
-
return [404, {
|
|
367
|
+
return [404, {Rack::CONTENT_TYPE => "text/plain", Web::X_CASCADE => "pass"}, ["Not Found"]] unless action
|
|
319
368
|
|
|
320
369
|
app = @klass
|
|
321
370
|
resp = catch(:halt) do
|
|
@@ -332,16 +381,21 @@ module Sidekiq
|
|
|
332
381
|
else
|
|
333
382
|
# rendered content goes here
|
|
334
383
|
headers = {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
384
|
+
Rack::CONTENT_TYPE => "text/html",
|
|
385
|
+
Rack::CACHE_CONTROL => "private, no-store",
|
|
386
|
+
Web::CONTENT_LANGUAGE => action.locale,
|
|
387
|
+
Web::CONTENT_SECURITY_POLICY => process_csp(env, CSP_HEADER_TEMPLATE),
|
|
388
|
+
Web::X_CONTENT_TYPE_OPTIONS => "nosniff"
|
|
339
389
|
}
|
|
340
390
|
# we'll let Rack calculate Content-Length for us.
|
|
341
391
|
[200, headers, [resp]]
|
|
342
392
|
end
|
|
343
393
|
end
|
|
344
394
|
|
|
395
|
+
def process_csp(env, input)
|
|
396
|
+
input.gsub("!placeholder!", env[:csp_nonce])
|
|
397
|
+
end
|
|
398
|
+
|
|
345
399
|
def self.helpers(mod = nil, &block)
|
|
346
400
|
if block
|
|
347
401
|
WebAction.class_eval(&block)
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
|
|
29
29
|
require "securerandom"
|
|
30
|
-
require "base64"
|
|
31
30
|
require "rack/request"
|
|
32
31
|
|
|
33
32
|
module Sidekiq
|
|
@@ -57,12 +56,12 @@ module Sidekiq
|
|
|
57
56
|
end
|
|
58
57
|
|
|
59
58
|
def logger(env)
|
|
60
|
-
@logger ||=
|
|
59
|
+
@logger ||= env["rack.logger"] || ::Logger.new(env["rack.errors"])
|
|
61
60
|
end
|
|
62
61
|
|
|
63
62
|
def deny(env)
|
|
64
63
|
logger(env).warn "attack prevented by #{self.class}"
|
|
65
|
-
[403, {
|
|
64
|
+
[403, {Rack::CONTENT_TYPE => "text/plain"}, ["Forbidden"]]
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
def session(env)
|
|
@@ -116,7 +115,7 @@ module Sidekiq
|
|
|
116
115
|
sess = session(env)
|
|
117
116
|
localtoken = sess[:csrf]
|
|
118
117
|
|
|
119
|
-
# Checks that Rack::Session::Cookie
|
|
118
|
+
# Checks that Rack::Session::Cookie actually contains the csrf token
|
|
120
119
|
return false if localtoken.nil?
|
|
121
120
|
|
|
122
121
|
# Rotate the session token after every use
|
|
@@ -143,7 +142,7 @@ module Sidekiq
|
|
|
143
142
|
one_time_pad = SecureRandom.random_bytes(token.length)
|
|
144
143
|
encrypted_token = xor_byte_strings(one_time_pad, token)
|
|
145
144
|
masked_token = one_time_pad + encrypted_token
|
|
146
|
-
|
|
145
|
+
encode_token(masked_token)
|
|
147
146
|
end
|
|
148
147
|
|
|
149
148
|
# Essentially the inverse of +mask_token+.
|
|
@@ -152,7 +151,7 @@ module Sidekiq
|
|
|
152
151
|
# value and decrypt it
|
|
153
152
|
token_length = masked_token.length / 2
|
|
154
153
|
one_time_pad = masked_token[0...token_length]
|
|
155
|
-
encrypted_token = masked_token[token_length
|
|
154
|
+
encrypted_token = masked_token[token_length..]
|
|
156
155
|
xor_byte_strings(one_time_pad, encrypted_token)
|
|
157
156
|
end
|
|
158
157
|
|
|
@@ -168,8 +167,12 @@ module Sidekiq
|
|
|
168
167
|
::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s)
|
|
169
168
|
end
|
|
170
169
|
|
|
170
|
+
def encode_token(token)
|
|
171
|
+
[token].pack("m0").tr("+/", "-_")
|
|
172
|
+
end
|
|
173
|
+
|
|
171
174
|
def decode_token(token)
|
|
172
|
-
|
|
175
|
+
token.tr("-_", "+/").unpack1("m0")
|
|
173
176
|
end
|
|
174
177
|
|
|
175
178
|
def xor_byte_strings(s1, s2)
|