Skip to content

Commit 75d6c6a

Browse files
authored
fix: Add additional payload filter key validation (#295)
Previously, we were allowing any non-empty string value to be provided as a payload filter key. However, customers can only create a filter key with a subset of characters within the LaunchDarkly UI. In an effort to warn customers earlier about potentially invalid configurations, we are adding basic key validation as part of the start up sequence.
1 parent 66f98d7 commit 75d6c6a

File tree

6 files changed

+70
-6
lines changed

6 files changed

+70
-6
lines changed

contract-tests/service.rb

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
'all-flags-client-side-only',
3232
'all-flags-details-only-for-tracked-flags',
3333
'filtering',
34+
'filtering-strict',
3435
'secure-mode-hash',
3536
'tags',
3637
'migrations',

launchdarkly-server-sdk.gemspec

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
2222
spec.required_ruby_version = ">= 3.0.0"
2323

2424
spec.add_development_dependency "aws-sdk-dynamodb", "~> 1.57"
25+
spec.add_development_dependency "rexml", "~> 3.3", ">= 3.3.7"
2526
spec.add_development_dependency "bundler", "2.2.33"
2627
spec.add_development_dependency "simplecov", "~> 0.21"
2728
spec.add_development_dependency "rspec", "~> 3.10"

lib/ldclient-rb/config.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def initialize(opts = {})
7777
@socket_factory = opts[:socket_factory]
7878
@big_segments = opts[:big_segments] || BigSegmentsConfig.new(store: nil)
7979
@application = LaunchDarkly::Impl::Util.validate_application_info(opts[:application] || {}, @logger)
80-
@payload_filter_key = opts[:payload_filter_key]
80+
@payload_filter_key = LaunchDarkly::Impl::Util.validate_payload_filter_key(opts[:payload_filter_key] , @logger)
8181
@hooks = (opts[:hooks] || []).keep_if { |hook| hook.is_a? Interfaces::Hooks::Hook }
8282
@omit_anonymous_contexts = opts.has_key?(:omit_anonymous_contexts) && opts[:omit_anonymous_contexts]
8383
@data_source_update_sink = nil

lib/ldclient-rb/impl/util.rb

+15
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ def self.validate_application_info(app, logger)
7575
version: validate_application_value(app[:version], :version, logger),
7676
}
7777
end
78+
79+
#
80+
# @param value [String, nil]
81+
# @param logger [Logger]
82+
# @return [String, nil]
83+
#
84+
def self.validate_payload_filter_key(value, logger)
85+
return nil if value.nil?
86+
return value if value.is_a?(String) && /^[a-zA-Z0-9][._\-a-zA-Z0-9]*$/.match?(value)
87+
88+
logger.warn {
89+
"Invalid payload filter configured, full environment will be fetched. Ensure the filter key is not empty and was copied correctly from LaunchDarkly settings."
90+
}
91+
nil
92+
end
7893
end
7994
end
8095
end

lib/ldclient-rb/util.rb

-5
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,6 @@ module Util
7777
def self.add_payload_filter_key(uri, config)
7878
return uri if config.payload_filter_key.nil?
7979

80-
unless config.payload_filter_key.is_a?(String) && !config.payload_filter_key.empty?
81-
config.logger.warn { "[LDClient] Filter key must be a non-empty string. No filtering will be applied." }
82-
return uri
83-
end
84-
8580
begin
8681
parsed = URI.parse(uri)
8782
new_query_params = URI.decode_www_form(String(parsed.query)) << ["filter", config.payload_filter_key]

spec/impl/util_spec.rb

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
require "spec_helper"
2+
3+
module LaunchDarkly
4+
module Impl
5+
describe "payload filter key validation" do
6+
let(:logger) { double }
7+
8+
it "silently discards nil" do
9+
expect(logger).not_to receive(:warn)
10+
expect(Util.validate_payload_filter_key(nil, logger)).to be_nil
11+
end
12+
13+
[true, 1, 1.0, [], {}].each do |value|
14+
it "returns nil for invalid type #{value.class}" do
15+
expect(logger).to receive(:warn)
16+
expect(Util.validate_payload_filter_key(value, logger)).to be_nil
17+
end
18+
end
19+
20+
[
21+
"",
22+
"-cannot-start-with-dash",
23+
"_cannot-start-with-underscore",
24+
"-cannot-start-with-period",
25+
"no spaces for you",
26+
"org@special/characters",
27+
].each do |value|
28+
it "returns nil for invalid value #{value}" do
29+
expect(logger).to receive(:warn)
30+
expect(Util.validate_payload_filter_key(value, logger)).to be_nil
31+
end
32+
end
33+
34+
[
35+
"camelCase",
36+
"snake_case",
37+
"kebab-case",
38+
"with.dots",
39+
"with_underscores",
40+
"with-hyphens",
41+
"with1234numbers",
42+
"with.many_1234-mixtures",
43+
"1start-with-number",
44+
].each do |value|
45+
it "passes for value #{value}" do
46+
expect(logger).not_to receive(:warn)
47+
expect(Util.validate_payload_filter_key(value, logger)).to eq(value)
48+
end
49+
end
50+
end
51+
end
52+
end

0 commit comments

Comments
 (0)