Skip to content

Instantly share code, notes, and snippets.

@ancorgs
Created February 10, 2017 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ancorgs/3a9c08313cc0ed52cc759ac94b21fa56 to your computer and use it in GitHub Desktop.
Save ancorgs/3a9c08313cc0ed52cc759ac94b21fa56 to your computer and use it in GitHub Desktop.
module Yast
# Mixin that enables a class to define attributes that are never exposed via
# #inspect, #to_s or similar methods, with the goal of preventing
# unintentional leaks of sensitive information in the application logs.
module SecretAttributes
# Inner class to store the value of the attribute without exposing it
# directly
class Attribute
def initialize(value)
@value = value
end
def value
@value
end
def to_s
value.nil? ? "nil" : "<secret>"
end
alias_method :inspect, :to_s
def instance_variables
# This adds even an extra barrier, just in case some formatter tries to
# use deep instrospection
[]
end
end
module ClassMethods
# Similar to .attr_accessor but with additional mechanisms to prevent
# exposing the internal value of the attribute
def secret_attr(name)
define_method(:"#{name}") do
attribute = instance_variable_get(:"@#{name}")
attribute ? attribute.value : nil
end
define_method(:"#{name}=") do |value|
instance_variable_set(:"@#{name}", Attribute.new(value))
value
end
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
end 71,3 Bo
module Yast
# Mixin that enables a class to define attributes that are never exposed via
# #inspect, #to_s or similar methods, with the goal of preventing
# unintentional leaks of sensitive information in the application logs.
module SecretAttributesAlt
module ClassMethods
# Similar to .attr_accessor but with additional mechanisms to prevent
# exposing the internal value of the attribute
def secret_attr(name)
# First, define the new method to nil by default
define_method(:"#{name}") do
nil
end
# When assigning the value, do not use an instance variable. Instead,
# dinamically re-define the getter method but just in the particular
# instance.
define_method(:"#{name}=") do |value|
(class << self; self; end).class_eval do
define_method(:"#{name}") do
value
end
end
end
@secret_attributes ||= []
@secret_attributes << name
end
# List of secret attributes for this class
def secret_attributes
@secret_attributes
end
end
alias_method :pre_secret_attributes_dup, :dup
# Redefined version of dup that, in addition to copying the instance
# variables, copies the secret attributes as well.
def dup
result = pre_secret_attributes_dup
self.class.secret_attributes.each do |attr|
result.send(:"#{attr}=", send(:"#{attr}"))
end
result
end
def self.included(base)
base.extend(ClassMethods)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment