sdk-reforge 1.10.0 → 1.11.2
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/CHANGELOG.md +9 -0
- data/VERSION +1 -1
- data/lib/reforge/encryption.rb +15 -6
- data/lib/reforge/sse_config_client.rb +7 -2
- data/sdk-reforge.gemspec +3 -3
- data/test/test_sse_config_client.rb +37 -3
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: de9767c4803726a6881d27e59b026d4a1e23d5592effae2f72908f44aed56e23
|
|
4
|
+
data.tar.gz: 16ab3c79d14b20136bb15cafd76b641f3dcced86c160a16681cf7666a564ec41
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c5e8a05f5f01014d9605c68648de26784d9190fdb3ab61d2c3ea55687a35feea851c5f50fbe86a3d21dfd8a0795df4644a656db04098988f8f3e7e030b117ae8
|
|
7
|
+
data.tar.gz: fe44f02ea0fffa0982732a4c581b50440ce174e2cd3798208820ca96b4ee2cfebe90e866d8566588c2d795b39bd505234bbd56340a2155869f740cdc60b8b15f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.11.2 - 2025-10-07
|
|
4
|
+
|
|
5
|
+
- Address OpenSSL issue with vulnerability to truncation attack
|
|
6
|
+
|
|
7
|
+
## 1.11.1 - 2025-10-06
|
|
8
|
+
|
|
9
|
+
- quiet logging for SSE reconnections
|
|
10
|
+
- let the SSE::Client handle the Last-Event-ID header
|
|
11
|
+
|
|
3
12
|
## 1.10.0 - 2025-10-02
|
|
4
13
|
|
|
5
14
|
- require `base64` for newest ruby versions
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.11.2
|
data/lib/reforge/encryption.rb
CHANGED
|
@@ -4,6 +4,7 @@ module Reforge
|
|
|
4
4
|
class Encryption
|
|
5
5
|
CIPHER_TYPE = "aes-256-gcm" # 32/12
|
|
6
6
|
SEPARATOR = "--"
|
|
7
|
+
AUTH_TAG_LENGTH = 16
|
|
7
8
|
|
|
8
9
|
# Hexadecimal format ensures that generated keys are representable with
|
|
9
10
|
# plain text
|
|
@@ -32,22 +33,30 @@ module Reforge
|
|
|
32
33
|
encrypted = cipher.update(clear_text)
|
|
33
34
|
encrypted << cipher.final
|
|
34
35
|
tag = cipher.auth_tag
|
|
35
|
-
|
|
36
|
+
|
|
36
37
|
# pack and join
|
|
37
38
|
[encrypted, iv, tag].map { |p| p.unpack("H*")[0] }.join(SEPARATOR)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def decrypt(encrypted_string)
|
|
41
|
-
|
|
42
|
+
encrypted_data, iv, auth_tag = encrypted_string.split(SEPARATOR).map { |p| [p].pack("H*") }
|
|
43
|
+
|
|
44
|
+
# Currently the OpenSSL bindings do not raise an error if auth_tag is
|
|
45
|
+
# truncated, which would allow an attacker to easily forge it. See
|
|
46
|
+
# https://github.com/ruby/openssl/issues/63
|
|
47
|
+
if auth_tag.bytesize != AUTH_TAG_LENGTH
|
|
48
|
+
raise "truncated auth_tag"
|
|
49
|
+
end
|
|
42
50
|
|
|
43
51
|
cipher = OpenSSL::Cipher.new(CIPHER_TYPE)
|
|
44
52
|
cipher.decrypt
|
|
45
53
|
cipher.key = @key
|
|
46
|
-
cipher.iv =
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
cipher.iv = iv
|
|
55
|
+
|
|
56
|
+
cipher.auth_tag = auth_tag
|
|
57
|
+
|
|
49
58
|
# and decrypt it
|
|
50
|
-
decrypted = cipher.update(
|
|
59
|
+
decrypted = cipher.update(encrypted_data)
|
|
51
60
|
decrypted << cipher.final
|
|
52
61
|
decrypted
|
|
53
62
|
end
|
|
@@ -72,6 +72,7 @@ module Reforge
|
|
|
72
72
|
headers: headers,
|
|
73
73
|
read_timeout: @options.sse_read_timeout,
|
|
74
74
|
reconnect_time: @options.sse_default_reconnect_time,
|
|
75
|
+
last_event_id: (@config_loader.highwater_mark&.positive? ? @config_loader.highwater_mark.to_s : nil),
|
|
75
76
|
logger: Reforge::InternalLogger.new(SSE::Client)) do |client|
|
|
76
77
|
client.on_event do |event|
|
|
77
78
|
if event.data.nil? || event.data.empty?
|
|
@@ -92,7 +93,12 @@ module Reforge
|
|
|
92
93
|
end
|
|
93
94
|
|
|
94
95
|
client.on_error do |error|
|
|
95
|
-
|
|
96
|
+
# SSL "unexpected eof" is expected when SSE sessions timeout normally
|
|
97
|
+
if error.is_a?(OpenSSL::SSL::SSLError) && error.message.include?('unexpected eof')
|
|
98
|
+
@logger.debug "SSE Streaming: Connection closed (expected timeout) for url #{url}"
|
|
99
|
+
else
|
|
100
|
+
@logger.error "SSE Streaming Error: #{error.inspect} for url #{url}"
|
|
101
|
+
end
|
|
96
102
|
|
|
97
103
|
if @options.errors_to_close_connection.any? { |klass| error.is_a?(klass) }
|
|
98
104
|
@logger.debug "Closing SSE connection for url #{url}"
|
|
@@ -106,7 +112,6 @@ module Reforge
|
|
|
106
112
|
auth = "#{AUTH_USER}:#{@prefab_options.sdk_key}"
|
|
107
113
|
auth_string = Base64.strict_encode64(auth)
|
|
108
114
|
return {
|
|
109
|
-
'Last-Event-ID' => @config_loader.highwater_mark,
|
|
110
115
|
'Authorization' => "Basic #{auth_string}",
|
|
111
116
|
'Accept' => 'text/event-stream',
|
|
112
117
|
'X-Reforge-SDK-Version' => "sdk-ruby-#{Reforge::VERSION}"
|
data/sdk-reforge.gemspec
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
|
5
|
-
# stub: sdk-reforge 1.
|
|
5
|
+
# stub: sdk-reforge 1.11.2 ruby lib
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.name = "sdk-reforge".freeze
|
|
9
|
-
s.version = "1.
|
|
9
|
+
s.version = "1.11.2"
|
|
10
10
|
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
12
12
|
s.require_paths = ["lib".freeze]
|
|
13
13
|
s.authors = ["Jeff Dwyer".freeze]
|
|
14
|
-
s.date = "2025-10-
|
|
14
|
+
s.date = "2025-10-07"
|
|
15
15
|
s.description = "Feature Flags, Live Config as a service".freeze
|
|
16
16
|
s.email = "jeff.dwyer@reforge.com.cloud".freeze
|
|
17
17
|
s.extra_rdoc_files = [
|
|
@@ -16,7 +16,6 @@ class TestSSEConfigClient < Minitest::Test
|
|
|
16
16
|
|
|
17
17
|
client = Reforge::SSEConfigClient.new(options, config_loader)
|
|
18
18
|
|
|
19
|
-
assert_equal 4, client.headers['Last-Event-ID']
|
|
20
19
|
assert_equal "https://stream.goatsofreforge.com", client.source
|
|
21
20
|
|
|
22
21
|
result = nil
|
|
@@ -48,8 +47,6 @@ class TestSSEConfigClient < Minitest::Test
|
|
|
48
47
|
|
|
49
48
|
client = Reforge::SSEConfigClient.new(prefab_options, config_loader, sse_options)
|
|
50
49
|
|
|
51
|
-
assert_equal 4, client.headers['Last-Event-ID']
|
|
52
|
-
|
|
53
50
|
result = nil
|
|
54
51
|
|
|
55
52
|
# fake our load_configs block
|
|
@@ -247,4 +244,41 @@ class TestSSEConfigClient < Minitest::Test
|
|
|
247
244
|
'Expected to have logged an error about empty data for nil'
|
|
248
245
|
mock_client.verify
|
|
249
246
|
end
|
|
247
|
+
|
|
248
|
+
def test_last_event_id_initialization
|
|
249
|
+
# Test with positive highwater_mark
|
|
250
|
+
config_loader = OpenStruct.new(highwater_mark: 42)
|
|
251
|
+
prefab_options = OpenStruct.new(sse_sources: ['http://localhost:4567'], sdk_key: 'test')
|
|
252
|
+
client = Reforge::SSEConfigClient.new(prefab_options, config_loader)
|
|
253
|
+
|
|
254
|
+
# Mock SSE::Client.new to capture the last_event_id argument
|
|
255
|
+
SSE::Client.stub :new, ->(*args, **kwargs, &block) {
|
|
256
|
+
assert_equal '42', kwargs[:last_event_id], 'Expected last_event_id to be "42"'
|
|
257
|
+
OpenStruct.new(closed?: false, close: nil)
|
|
258
|
+
} do
|
|
259
|
+
client.connect { |_configs, _event, _source| }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Test with nil highwater_mark
|
|
263
|
+
config_loader = OpenStruct.new(highwater_mark: nil)
|
|
264
|
+
client = Reforge::SSEConfigClient.new(prefab_options, config_loader)
|
|
265
|
+
|
|
266
|
+
SSE::Client.stub :new, ->(*args, **kwargs, &block) {
|
|
267
|
+
assert_nil kwargs[:last_event_id], 'Expected last_event_id to be nil when highwater_mark is nil'
|
|
268
|
+
OpenStruct.new(closed?: false, close: nil)
|
|
269
|
+
} do
|
|
270
|
+
client.connect { |_configs, _event, _source| }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Test with zero highwater_mark
|
|
274
|
+
config_loader = OpenStruct.new(highwater_mark: 0)
|
|
275
|
+
client = Reforge::SSEConfigClient.new(prefab_options, config_loader)
|
|
276
|
+
|
|
277
|
+
SSE::Client.stub :new, ->(*args, **kwargs, &block) {
|
|
278
|
+
assert_nil kwargs[:last_event_id], 'Expected last_event_id to be nil when highwater_mark is 0'
|
|
279
|
+
OpenStruct.new(closed?: false, close: nil)
|
|
280
|
+
} do
|
|
281
|
+
client.connect { |_configs, _event, _source| }
|
|
282
|
+
end
|
|
283
|
+
end
|
|
250
284
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sdk-reforge
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.11.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeff Dwyer
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2025-10-
|
|
10
|
+
date: 2025-10-07 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: concurrent-ruby
|