tidus 1.0.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ef15fa25eadfd7fd12896aa48d5106c10c2d743
4
- data.tar.gz: 2e9e30f4a43c97913a518b13f0efaa987bb30dbf
3
+ metadata.gz: 16d22e9b2bf400af04c3c38e0d230a19134edf46
4
+ data.tar.gz: c8c0389b398d87c9b440efc68eb2586263137241
5
5
  SHA512:
6
- metadata.gz: 6359526ca259d737809d0161f1800f067ea626e7231302b0f892114f7d011496f0e807040cf55c7a775bacba1c3d276d4d66e3adacd92663fba7821921683175
7
- data.tar.gz: 41dd5744e5290b3fd8752710f664a7afeba92f6dec2ba8bfe03b301b9c1a1a9f6e413be15c4764af51ff39e575ce8738001bfea4d1768f78c5cc6fadd8bb5699
6
+ metadata.gz: 2633f5e90d829abb8e8a598302f54f5dc22def128e1b74d48b94300992fb3e80f85008f456d1906b40c36edef3e5400bb13035eeffca2c6e873854745d59eb48
7
+ data.tar.gz: 11cdfd7de96c1d7ad031d452b8c5c9f100e6dfbaeba35a5524bc709f86b083a6e9c7720f04b70ff931fc22f7ff87f2c5950d260e95d581a735689f062b8fe242
data/lib/tasks/views.rake CHANGED
@@ -6,9 +6,7 @@ namespace :db do
6
6
  next if c.table_name == "schema_migrations"
7
7
  puts "Clearing view '#{c.view_name}' for table '#{c.table_name}'"
8
8
 
9
- ActiveRecord::Base.connection.execute(
10
- "DROP VIEW IF EXISTS #{c.view_name}"
11
- )
9
+ c.clear_view
12
10
  end
13
11
  end
14
12
 
@@ -21,11 +19,7 @@ namespace :db do
21
19
  if ActiveRecord::Base.connection.table_exists? c.table_name
22
20
  puts "Generating view '#{c.view_name}' for table '#{c.table_name}'"
23
21
 
24
- ActiveRecord::Base.connection.execute(
25
- "CREATE VIEW #{c.view_name} AS " +
26
- "(SELECT #{c.view_columns.join(', ')} " +
27
- "FROM #{c.table_name})"
28
- )
22
+ c.create_view
29
23
  end
30
24
  end
31
25
  end
data/lib/tidus.rb CHANGED
@@ -1,14 +1,13 @@
1
+ # encoding: utf-8
2
+
1
3
  require "rake"
2
4
  require "active_record"
3
5
 
4
6
  require "tidus/version"
7
+ require "tidus/query"
5
8
  require "tidus/anonymization"
6
- require "tidus/strategies/cond_anonymizer.rb"
7
- require "tidus/strategies/email_anonymizer.rb"
8
- require "tidus/strategies/null_anonymizer.rb"
9
- require "tidus/strategies/overlay_anonymizer.rb"
10
- require "tidus/strategies/static_anonymizer.rb"
11
- require "tidus/strategies/text_anonymizer.rb"
9
+ require "tidus/strategies/base_selector"
10
+ Dir["#{File.dirname(__FILE__)}/tidus/strategies/**/*.rb"].each { |f| require f }
12
11
 
13
12
  load "active_record/railties/databases.rake"
14
13
  load "tasks/views.rake"
@@ -1,5 +1,9 @@
1
+ # encoding: utf-8
2
+
1
3
  module Tidus
2
4
  module Anonymization
5
+ include Tidus::Query
6
+
3
7
  def view_postfix
4
8
  @view_postfix || "anonymized"
5
9
  end
@@ -37,8 +41,8 @@ module Tidus
37
41
  options = attributes.extract_options!.dup
38
42
  columns = attributes - [options]
39
43
 
40
- raise ArgumentError, "You need to supply at least one attribute" if attributes.empty?
41
- raise ArgumentError, "You need to supply a strategy" if options[:strategy].blank?
44
+ raise ArgumentError, "Must have at least one attribute" if attributes.empty?
45
+ raise ArgumentError, "Must have a strategy" if options[:strategy].blank?
42
46
 
43
47
  columns.each do |column|
44
48
  key = options[:strategy].to_s.camelize
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ module Tidus
4
+ module Query
5
+ def create_query
6
+ "CREATE VIEW #{view_name} AS " +
7
+ "SELECT #{view_columns.join(', ')} " +
8
+ "FROM #{table_name}"
9
+ end
10
+
11
+ def create_view
12
+ connection.execute(create_query)
13
+ end
14
+
15
+ def clear_query
16
+ "DROP VIEW IF EXISTS #{view_name}"
17
+ end
18
+
19
+ def clear_view
20
+ connection.execute(clear_query)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Tidus
4
+ class BaseSelector
5
+ def self.anonymize(table_name, column_name, options = {})
6
+ adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
7
+
8
+ begin
9
+ klass = Kernel.const_get("Tidus::#{adapter.camelize}::#{self.name.demodulize}")
10
+ klass.anonymize(table_name, column_name, options)
11
+ rescue NameError
12
+ raise "#{self.name} not implemented for #{adapter}"
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -1,44 +1,6 @@
1
- module Tidus
2
- class CondAnonymizer
3
- def self.anonymize(table_name, column_name, options = {})
4
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
5
- case adapter
6
- when "postgresql"
7
- name = "#{table_name}.#{column_name}"
8
-
9
- type = options[:result_type] || "text"
10
- default = options[:default].nil? ? "#{name}::#{type}" : "'#{options[:default]}'::#{type}"
11
-
12
- if options[:conditions].blank?
13
- raise "Missing option :conditions for CondAnonymizer on #{name}"
14
- elsif options[:conditions].kind_of?(Array)
15
- conditions = options[:conditions]
16
- else
17
- conditions = [options[:conditions]]
18
- end
19
-
20
- command = "CASE "
1
+ # encoding: utf-8
21
2
 
22
- conditions.each do |cond|
23
- raise ":column for condition must be set" if cond[:column].blank?
24
- raise ":value for condition must be set" if cond[:value].nil?
25
- raise ":result for condition must be set" if cond[:result].nil?
26
- cond_column = cond[:column]
27
- cond_value = cond[:value]
28
- cond_type = cond[:type] || "text"
29
- comparator = cond[:comparator] || "="
30
- cond_result = cond[:result]
31
-
32
- command += "WHEN ((#{table_name}.#{cond_column})::#{cond_type} #{comparator} " +
33
- "'#{cond_value}'::#{cond_type}) THEN '#{cond_result}'::#{type} "
34
- end
35
-
36
- command += "ELSE #{default} END"
37
-
38
- return command
39
- else
40
- raise "#{self.name} not implemented for #{adapter}"
41
- end
42
- end
3
+ module Tidus
4
+ class CondAnonymizer < Tidus::BaseSelector
43
5
  end
44
6
  end
@@ -1,20 +1,7 @@
1
- module Tidus
2
- class EmailAnonymizer
3
- def self.anonymize(table_name, column_name, options = {})
4
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
5
- case adapter
6
- when "postgresql"
7
- name = "#{table_name}.#{column_name}"
8
- options[:length] ||= 15
1
+ # encoding: utf-8
9
2
 
10
- return "CASE WHEN ((#{name})::text ~~ '%@%'::text) " +
11
- "THEN (((\"left\"(md5((#{name})::text), #{options[:length]}) || '@'::text) " +
12
- "|| split_part((#{name})::text, '@'::text, 2)))::character varying " +
13
- "ELSE #{name} END"
14
- else
15
- raise "#{self.name} not implemented for #{adapter}"
16
- end
17
- end
3
+ module Tidus
4
+ class EmailAnonymizer < Tidus::BaseSelector
18
5
  end
19
6
  end
20
7
 
@@ -1,13 +1,6 @@
1
+ # encoding: utf-8
2
+
1
3
  module Tidus
2
- class NullAnonymizer
3
- def self.anonymize(table_name, column_name, options = {})
4
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
5
- case adapter
6
- when "postgresql"
7
- return "NULL::unknown"
8
- else
9
- raise "#{self.name} not implemented for #{adapter}"
10
- end
11
- end
4
+ class NullAnonymizer < Tidus::BaseSelector
12
5
  end
13
6
  end
@@ -1,21 +1,6 @@
1
- module Tidus
2
- class OverlayAnonymizer
3
- def self.anonymize(table_name, column_name, options = {})
4
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
5
- case adapter
6
- when "postgresql"
7
- name = "#{table_name}.#{column_name}"
8
-
9
- raise "Missing option :start for OverlayAnonymizer on #{name}" if options[:start].blank?
10
- raise "Missing option :length for OverlayAnonymizer on #{name}" if options[:length].blank?
1
+ # encoding: utf-8
11
2
 
12
- overlay_char = options[:char] || "X"
13
- overlay = overlay_char * options[:length]
14
- return "\"overlay\"((#{name})::text, " +
15
- "'#{overlay}'::text, #{options[:start]})"
16
- else
17
- raise "#{self.name} not implemented for #{adapter}"
18
- end
19
- end
3
+ module Tidus
4
+ class OverlayAnonymizer < Tidus::BaseSelector
20
5
  end
21
6
  end
@@ -0,0 +1,40 @@
1
+ module Tidus
2
+ module Postgresql
3
+ class CondAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ name = "#{table_name}.#{column_name}"
6
+
7
+ type = options[:result_type] || "text"
8
+ default = options[:default].nil? ? "#{name}::#{type}" : "'#{options[:default]}'::#{type}"
9
+
10
+ if options[:conditions].blank?
11
+ raise "Missing option :conditions for CondAnonymizer on #{name}"
12
+ elsif options[:conditions].kind_of?(Array)
13
+ conditions = options[:conditions]
14
+ else
15
+ conditions = [options[:conditions]]
16
+ end
17
+
18
+ command = "CASE "
19
+
20
+ conditions.each do |cond|
21
+ raise ":column for condition must be set" if cond[:column].blank?
22
+ raise ":value for condition must be set" if cond[:value].nil?
23
+ raise ":result for condition must be set" if cond[:result].nil?
24
+ cond_column = cond[:column]
25
+ cond_value = cond[:value]
26
+ cond_type = cond[:type] || "text"
27
+ comparator = cond[:comparator] || "="
28
+ cond_result = cond[:result]
29
+
30
+ command += "WHEN ((#{table_name}.#{cond_column})::#{cond_type} #{comparator} " +
31
+ "'#{cond_value}'::#{cond_type}) THEN '#{cond_result}'::#{type} "
32
+ end
33
+
34
+ command += "ELSE #{default} END"
35
+
36
+ return command
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module Tidus
2
+ module Postgresql
3
+ class EmailAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ name = "#{table_name}.#{column_name}"
6
+ options[:length] ||= 15
7
+
8
+ return "CASE WHEN ((#{name})::text ~~ '%@%'::text) " +
9
+ "THEN (((\"left\"(md5((#{name})::text), #{options[:length]}) || '@'::text) " +
10
+ "|| split_part((#{name})::text, '@'::text, 2)))::character varying " +
11
+ "ELSE #{name} END"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Tidus
2
+ module Postgresql
3
+ class NullAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ return "NULL::unknown"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Tidus
2
+ module Postgresql
3
+ class OverlayAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ name = "#{table_name}.#{column_name}"
6
+
7
+ raise "Missing option :start for OverlayAnonymizer on #{name}" if options[:start].blank?
8
+ raise "Missing option :length for OverlayAnonymizer on #{name}" if options[:length].blank?
9
+
10
+ overlay_char = options[:char] || "X"
11
+ overlay = overlay_char * options[:length]
12
+ return "\"overlay\"((#{name})::text, " +
13
+ "'#{overlay}'::text, #{options[:start]})"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ module Tidus
2
+ module Postgresql
3
+ class TextAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZCßüäöÜÄÖ"
6
+ return "translate((#{table_name}.#{column_name})::text, " +
7
+ "'#{base}'::text, '#{generate_mapping(base)}'::text)"
8
+ end
9
+
10
+ private
11
+ def self.generate_mapping(base)
12
+ upper = ("A".."Z").to_a
13
+ lower = ("a".."z").to_a
14
+ result = base.split("").map do |letter|
15
+ if letter == letter.upcase
16
+ upper.sample
17
+ else
18
+ lower.sample
19
+ end
20
+ end
21
+ result.join("")
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ module Tidus
2
+ module Sqlite3
3
+ class NullAnonymizer
4
+ def self.anonymize(table_name, column_name, options = {})
5
+ return "NULL"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,15 +1,12 @@
1
+ # encoding: utf-8
2
+
1
3
  module Tidus
2
4
  class StaticAnonymizer
3
5
  def self.anonymize(table_name, column_name, options = {})
4
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
5
- case adapter
6
- when "postgresql"
7
- raise "Missing option :value for StaticAnonymizer on #{table_name}.#{column_name}" if options[:value].blank?
6
+ raise "Missing option :value for StaticAnonymizer on #{table_name}.#{column_name}" if options[:value].blank?
7
+ type = options[:type] || "unknown"
8
8
 
9
- return "'#{options[:value]}'"
10
- else
11
- raise "#{self.name} not implemented for #{adapter}"
12
- end
9
+ return "'#{options[:value]}'::#{type}"
13
10
  end
14
11
  end
15
12
  end
@@ -1,28 +1,6 @@
1
- module Tidus
2
- class TextAnonymizer
3
- def self.anonymize(table_name, column_name, options = {})
4
- base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZCßüäöÜÄÖ"
5
- adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
6
- case adapter
7
- when "postgresql"
8
- return "translate((#{table_name}.#{column_name})::text, " +
9
- "'#{base}'::text, '#{generate_mapping(base)}'::text)"
10
- else
11
- raise "#{self.name} not implemented for #{adapter}"
12
- end
13
- end
1
+ # encoding: utf-8
14
2
 
15
- private
16
- def self.generate_mapping(base)
17
- result = ""
18
- base.split("").each do |letter|
19
- if letter == letter.upcase
20
- result += ("A".."Z").to_a.shuffle.first
21
- else
22
- result += ("a".."z").to_a.shuffle.first
23
- end
24
- end
25
- result
26
- end
3
+ module Tidus
4
+ class TextAnonymizer < Tidus::BaseSelector
27
5
  end
28
6
  end
data/lib/tidus/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Tidus
2
- VERSION = "1.0.1"
2
+ VERSION = "1.0.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tidus
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schoknecht
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-09 00:00:00.000000000 Z
11
+ date: 2015-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -76,10 +76,18 @@ files:
76
76
  - lib/tasks/views.rake
77
77
  - lib/tidus.rb
78
78
  - lib/tidus/anonymization.rb
79
+ - lib/tidus/query.rb
80
+ - lib/tidus/strategies/base_selector.rb
79
81
  - lib/tidus/strategies/cond_anonymizer.rb
80
82
  - lib/tidus/strategies/email_anonymizer.rb
81
83
  - lib/tidus/strategies/null_anonymizer.rb
82
84
  - lib/tidus/strategies/overlay_anonymizer.rb
85
+ - lib/tidus/strategies/postgresql/cond_anonymizer.rb
86
+ - lib/tidus/strategies/postgresql/email_anonymizer.rb
87
+ - lib/tidus/strategies/postgresql/null_anonymizer.rb
88
+ - lib/tidus/strategies/postgresql/overlay_anonymizer.rb
89
+ - lib/tidus/strategies/postgresql/text_anonymizer.rb
90
+ - lib/tidus/strategies/sqlite3/null_anonymizer.rb
83
91
  - lib/tidus/strategies/static_anonymizer.rb
84
92
  - lib/tidus/strategies/text_anonymizer.rb
85
93
  - lib/tidus/version.rb
@@ -103,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
111
  version: '0'
104
112
  requirements: []
105
113
  rubyforge_project:
106
- rubygems_version: 2.4.5
114
+ rubygems_version: 2.4.6
107
115
  signing_key:
108
116
  specification_version: 4
109
117
  summary: Gem for creating anonymization views.