diff --git a/lib/ldclient-rb/impl/context_filter.rb b/lib/ldclient-rb/impl/context_filter.rb index bec00400..4c7ea891 100644 --- a/lib/ldclient-rb/impl/context_filter.rb +++ b/lib/ldclient-rb/impl/context_filter.rb @@ -100,13 +100,13 @@ def filter_redact_anonymous(context) # private def check_whole_attribute_private(attribute, private_attributes, redacted, redact_all) if @all_attributes_private || redact_all - redacted << attribute + redacted << redaction_name(attribute) return true end private_attributes.each do |private_attribute| if private_attribute.component(0) == attribute && private_attribute.depth == 1 - redacted << attribute + redacted << redaction_name(attribute) return true end end @@ -114,6 +114,17 @@ def filter_redact_anonymous(context) false end + # + # Convert an attribute name into the attribute reference used to report it + # as redacted. + # + # @param attribute [Symbol] + # @return [Symbol] + # + private def redaction_name(attribute) + LaunchDarkly::Reference.create_literal(attribute).raw_path.to_sym + end + # # Apply redaction rules to the provided value. # diff --git a/spec/impl/context_filter_spec.rb b/spec/impl/context_filter_spec.rb new file mode 100644 index 00000000..9d3c41b2 --- /dev/null +++ b/spec/impl/context_filter_spec.rb @@ -0,0 +1,35 @@ +require "spec_helper" + +module LaunchDarkly + module Impl + describe ContextFilter do + it "reports redacted attribute names as escaped attribute references" do + filter = ContextFilter.new(true, []) + context = LDContext.create({ kind: "user", key: "user-key", :"/ssn" => "123-45-6789", :"a/b~c" => "value" }) + + filtered = filter.filter(context) + + expect(filtered[:_meta][:redactedAttributes]).to contain_exactly(:"/~1ssn", :"a/b~c") + end + + it "escapes redacted attribute names when redacting anonymous contexts" do + filter = ContextFilter.new(false, []) + context = LDContext.create({ kind: "user", key: "user-key", anonymous: true, name: "name", :"/ssn" => "123-45-6789" }) + + filtered = filter.filter_redact_anonymous(context) + + expect(filtered[:_meta][:redactedAttributes]).to contain_exactly(:name, :"/~1ssn") + end + + it "escapes redacted attribute names configured as private" do + filter = ContextFilter.new(false, ["/~1ssn"]) + context = LDContext.create({ kind: "user", key: "user-key", :"/ssn" => "123-45-6789", name: "name" }) + + filtered = filter.filter(context) + + expect(filtered[:name]).to eq("name") + expect(filtered[:_meta][:redactedAttributes]).to eq([:"/~1ssn"]) + end + end + end +end