Class: MyObfuscate
- Inherits:
-
Object
- Object
- MyObfuscate
- Defined in:
- lib/my_obfuscate.rb
Constant Summary collapse
- INSERT_REGEX =
/^\s*INSERT INTO `(.*?)` \((.*?)\) VALUES\s*/i
- NUMBER_CHARS =
"1234567890"
- USERNAME_CHARS =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_" + NUMBER_CHARS
- SENSIBLE_CHARS =
USERNAME_CHARS + '+-=[{]}/?|!@#$%^&*()`~'
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
Class Method Summary collapse
- .apply_table_config(row, table_config, columns) ⇒ Object
-
.context_aware_mysql_string_split(string) ⇒ Object
Note: Strings must be quoted in single quotes!.
- .random_integer(between) ⇒ Object
- .random_string(length_or_range, chars) ⇒ Object
- .reasembling_each_insert(line, table_name, columns) ⇒ Object
Instance Method Summary collapse
- #check_for_missing_columns(table_name, columns) ⇒ Object
-
#initialize(configuration = {}) ⇒ MyObfuscate
constructor
A new instance of MyObfuscate.
-
#obfuscate(input_io, output_io) ⇒ Object
We assume that every INSERT INTO line occupies one line in the file, with no internal linebreaks.
- #obfuscate_line(line, table_name, columns) ⇒ Object
Constructor Details
#initialize(configuration = {}) ⇒ MyObfuscate
Returns a new instance of MyObfuscate.
12 13 14 |
# File 'lib/my_obfuscate.rb', line 12 def initialize(configuration = {}) @config = configuration end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
5 6 7 |
# File 'lib/my_obfuscate.rb', line 5 def config @config end |
Class Method Details
.apply_table_config(row, table_config, columns) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/my_obfuscate.rb', line 106 def self.apply_table_config(row, table_config, columns) return row unless table_config.is_a?(Hash) table_config.each do |column, definition| # Don't change email addresses when they end in @honk.com. index = columns.index(column) if definition[:skip_regexes] next if definition[:skip_regexes].any? {|regex| row[index] =~ regex} end row[index.to_i] = case definition[:type] when :email random_string(4..10, USERNAME_CHARS) + "@example.com" when :string random_string(definition[:length], definition[:chars] || SENSIBLE_CHARS) when :integer random_integer(definition[:between] || (0..1000)).to_s when :fixed if definition[:one_of] definition[:one_of][(rand * definition[:one_of].length).to_i] else definition[:string] end when :null nil else row[index] end end row end |
.context_aware_mysql_string_split(string) ⇒ Object
Note: Strings must be quoted in single quotes!
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/my_obfuscate.rb', line 51 def self.context_aware_mysql_string_split(string) in_sub_insert = false in_quoted_string = false escaped = false current_field = nil length = string.length index = 0 fields = [] output = [] string.each_char do |i| if escaped escaped = false current_field ||= "" current_field << i else if i == "\\" escaped = true current_field ||= "" current_field << i elsif i == "(" && !in_quoted_string && !in_sub_insert in_sub_insert = true elsif i == ")" && !in_quoted_string && in_sub_insert fields << current_field unless current_field.nil? output << fields unless fields.length == 0 in_sub_insert = false fields = [] current_field = nil elsif i == "'" && !in_quoted_string fields << current_field unless current_field.nil? current_field = '' in_quoted_string = true elsif i == "'" && in_quoted_string fields << current_field unless current_field.nil? current_field = nil in_quoted_string = false elsif i == "," && !in_quoted_string && in_sub_insert fields << current_field unless current_field.nil? current_field = nil elsif i == "L" && !in_quoted_string && in_sub_insert && current_field == "NUL" current_field = nil fields << current_field elsif (i == " " || i == "\t") && !in_quoted_string # Don't add whitespace not in a string elsif in_sub_insert current_field ||= "" current_field << i end end index += 1 end fields << current_field unless current_field.nil? output << fields unless fields.length == 0 output end |
.random_integer(between) ⇒ Object
139 140 141 |
# File 'lib/my_obfuscate.rb', line 139 def self.random_integer(between) (between.min + (between.max - between.min) * rand).round end |
.random_string(length_or_range, chars) ⇒ Object
143 144 145 146 147 148 149 |
# File 'lib/my_obfuscate.rb', line 143 def self.random_string(length_or_range, chars) length_or_range = (length_or_range..length_or_range) if length_or_range.is_a?(Fixnum) times = random_integer(length_or_range) out = "" times.times { out << chars[rand * chars.length] } out end |
.reasembling_each_insert(line, table_name, columns) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/my_obfuscate.rb', line 33 def self.reasembling_each_insert(line, table_name, columns) line = line.gsub(INSERT_REGEX, '').gsub(/\s*;\s*$/, '') output = context_aware_mysql_string_split(line).map do |sub_insert| result = yield(sub_insert) result = result.map do |i| if i.nil? "NULL" else "'" + i + "'" end end result = result.join(",") "(" + result + ")" end.join(",") "INSERT INTO `#{table_name}` (`#{columns.join('`, `')}`) VALUES #{output};" end |
Instance Method Details
#check_for_missing_columns(table_name, columns) ⇒ Object
151 152 153 154 155 156 157 158 159 |
# File 'lib/my_obfuscate.rb', line 151 def check_for_missing_columns(table_name, columns) missing_columns = config[table_name].keys - columns unless missing_columns.length == 0 = missing_columns.map do |missing_column| "Column '#{missing_column}' could not be found in table '#{table_name}', please fix your obfuscator config." end.join("\n") raise RuntimeError.new() end end |
#obfuscate(input_io, output_io) ⇒ Object
We assume that every INSERT INTO line occupies one line in the file, with no internal linebreaks.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/my_obfuscate.rb', line 17 def obfuscate(input_io, output_io) input_io.each do |line| if regex_result = INSERT_REGEX.match(line) table_name = regex_result[1].to_sym columns = regex_result[2].split(/`\s*,\s*`/).map { |col| col.gsub('`',"").to_sym } if config[table_name] output_io.puts obfuscate_line(line, table_name, columns) else output_io.write line end else output_io.write line end end end |
#obfuscate_line(line, table_name, columns) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/my_obfuscate.rb', line 161 def obfuscate_line(line, table_name, columns) table_config = config[table_name] if table_config == :truncate "" else check_for_missing_columns(table_name, columns) # Note: Remember to SQL escape strings in what you pass back. MyObfuscate.reasembling_each_insert(line, table_name, columns) do |row| MyObfuscate.apply_table_config(row, table_config, columns) end end end |