pgcrypto 0.3.6 → 0.4.1

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +5 -1
  3. data/Gemfile +1 -4
  4. data/README.markdown +126 -33
  5. data/VERSION +1 -1
  6. data/lib/active_record/connection_adapters/pgcrypto_adapter.rb +4 -0
  7. data/lib/active_record/connection_adapters/pgcrypto_adapter/rails_3.rb +20 -0
  8. data/lib/active_record/connection_adapters/pgcrypto_adapter/rails_4.rb +22 -0
  9. data/lib/pgcrypto.rb +15 -105
  10. data/lib/pgcrypto/adapter.rb +162 -0
  11. data/lib/pgcrypto/column.rb +9 -8
  12. data/lib/pgcrypto/column_converter.rb +26 -0
  13. data/lib/pgcrypto/generators/base_generator.rb +12 -0
  14. data/lib/{generators/pgcrypto → pgcrypto/generators}/install/USAGE +0 -0
  15. data/lib/{generators/pgcrypto → pgcrypto/generators}/install/install_generator.rb +2 -5
  16. data/lib/{generators/pgcrypto → pgcrypto/generators}/install/templates/initializer.rb +0 -0
  17. data/lib/pgcrypto/generators/install/templates/migration.rb +5 -0
  18. data/lib/pgcrypto/generators/upgrade/USAGE +8 -0
  19. data/lib/pgcrypto/generators/upgrade/templates/migration.rb +22 -0
  20. data/lib/pgcrypto/generators/upgrade/upgrade_generator.rb +15 -0
  21. data/lib/pgcrypto/has_encrypted_column.rb +25 -0
  22. data/lib/pgcrypto/key.rb +0 -10
  23. data/lib/pgcrypto/key_manager.rb +11 -0
  24. data/lib/pgcrypto/railtie.rb +15 -0
  25. data/lib/pgcrypto/table.rb +11 -0
  26. data/lib/pgcrypto/table_manager.rb +2 -10
  27. data/lib/tasks/pgcrypto.rake +7 -0
  28. data/pgcrypto.gemspec +24 -17
  29. data/spec/lib/pgcrypto_spec.rb +101 -100
  30. data/spec/spec_helper.rb +27 -28
  31. metadata +20 -36
  32. data/lib/generators/pgcrypto/install/templates/migration.rb +0 -17
  33. data/lib/pgcrypto/active_record.rb +0 -88
  34. data/lib/pgcrypto/arel.rb +0 -24
@@ -1,24 +1,28 @@
1
+ require 'rubygems'
2
+ require 'simplecov'
3
+
1
4
  # Add lib/ to the load path
2
5
  $LOAD_PATH.unshift(File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__)))
3
6
 
4
- # Load up our Gemfile
5
- require 'rubygems'
6
- require 'bundler/setup'
7
- Bundler.require(:default, :test)
8
-
9
- # Enable coverage reporting
10
- require 'simplecov'
7
+ require 'database_cleaner'
8
+ require 'pry'
11
9
 
12
- # Requier and configure PGCrypto
10
+ gem 'activerecord', ENV.fetch('ACTIVE_RECORD_VERSION', '>= 4.0')
11
+ require 'active_record'
13
12
  require 'pgcrypto'
14
13
 
15
14
  RSpec.configure do |config|
16
- database_config = {:adapter => 'postgresql', :database => 'pgcrypto_test', :encoding => 'utf8', :host => 'localhost'}
15
+ database_config = {
16
+ adapter: 'pgcrypto',
17
+ database: '__pgcrypto_gem_test',
18
+ encoding: 'utf8',
19
+ host: 'localhost'
20
+ }
17
21
  postgres_config = database_config.merge(:database => 'postgres', :schema_search_path => 'public')
18
22
 
19
23
  # Set up the database to handle pgcrypto functions and the schema for
20
24
  # our tests
21
- config.before :all do
25
+ config.before :suite do
22
26
  # Connect to the local postgres schema database
23
27
  ActiveRecord::Base.establish_connection(postgres_config)
24
28
 
@@ -30,44 +34,39 @@ RSpec.configure do |config|
30
34
 
31
35
  silence_stream(STDOUT) do
32
36
  # ...and load in the pgcrypto extension
33
- ActiveRecord::Base.connection.execute(%[CREATE EXTENSION pgcrypto])
37
+ ActiveRecord::Base.connection.execute(%[CREATE EXTENSION pgcrypto]) rescue nil
34
38
 
35
39
  # ...and then set up the pgcrypto_columns and pgcrypto_test_models fun
36
40
  ActiveRecord::Schema.define do
37
- create_table :pgcrypto_columns, :force => true do |t|
38
- t.belongs_to :owner, :polymorphic => true
39
- t.string :owner_table, :limit => 32
40
- t.string :name, :limit => 64
41
- t.binary :value
42
- end
43
-
44
41
  create_table :pgcrypto_test_models, :force => true do |t|
45
42
  t.string :name, :limit => 32
43
+ t.binary :encrypted_text
46
44
  end
47
45
  end
48
46
  end
47
+
48
+ ActiveRecord::Base.establish_connection(database_config)
49
+
50
+ DatabaseCleaner.strategy = :transaction
49
51
  end
50
52
 
51
53
  config.before :each do
52
- DatabaseCleaner.strategy = :transaction
53
- DatabaseCleaner.clean_with :transaction
54
54
  DatabaseCleaner.start
55
55
 
56
- ActiveRecord::Base.establish_connection(database_config)
57
-
58
56
  class PGCryptoTestModel < ActiveRecord::Base
59
57
  self.table_name = :pgcrypto_test_models
60
- pgcrypto :test_column
58
+ has_encrypted_column :encrypted_text
61
59
  end
62
60
  end
63
61
 
64
- config.after :all do
65
- # Drop the database when we exist
62
+ config.after :each do
63
+ DatabaseCleaner.clean
64
+ end
65
+
66
+ config.after :suite do
67
+ # Drop the database when we exit
66
68
  ActiveRecord::Base.establish_connection(postgres_config)
67
69
  ActiveRecord::Base.connection.drop_database(database_config[:database]) rescue nil
68
70
  end
69
71
 
70
- config.after :each do
71
- DatabaseCleaner.clean
72
- end
73
72
  end
metadata CHANGED
@@ -1,43 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgcrypto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Flip Sasser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-22 00:00:00.000000000 Z
11
+ date: 2014-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activerecord
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '3.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '3.2'
27
- - !ruby/object:Gem::Dependency
28
- name: big_spoon
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 0.2.1
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 0.2.1
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: jeweler
43
15
  requirement: !ruby/object:Gem::Requirement
@@ -71,16 +43,28 @@ files:
71
43
  - README.markdown
72
44
  - Rakefile
73
45
  - VERSION
74
- - lib/generators/pgcrypto/install/USAGE
75
- - lib/generators/pgcrypto/install/install_generator.rb
76
- - lib/generators/pgcrypto/install/templates/initializer.rb
77
- - lib/generators/pgcrypto/install/templates/migration.rb
46
+ - lib/active_record/connection_adapters/pgcrypto_adapter.rb
47
+ - lib/active_record/connection_adapters/pgcrypto_adapter/rails_3.rb
48
+ - lib/active_record/connection_adapters/pgcrypto_adapter/rails_4.rb
78
49
  - lib/pgcrypto.rb
79
- - lib/pgcrypto/active_record.rb
80
- - lib/pgcrypto/arel.rb
50
+ - lib/pgcrypto/adapter.rb
81
51
  - lib/pgcrypto/column.rb
52
+ - lib/pgcrypto/column_converter.rb
53
+ - lib/pgcrypto/generators/base_generator.rb
54
+ - lib/pgcrypto/generators/install/USAGE
55
+ - lib/pgcrypto/generators/install/install_generator.rb
56
+ - lib/pgcrypto/generators/install/templates/initializer.rb
57
+ - lib/pgcrypto/generators/install/templates/migration.rb
58
+ - lib/pgcrypto/generators/upgrade/USAGE
59
+ - lib/pgcrypto/generators/upgrade/templates/migration.rb
60
+ - lib/pgcrypto/generators/upgrade/upgrade_generator.rb
61
+ - lib/pgcrypto/has_encrypted_column.rb
82
62
  - lib/pgcrypto/key.rb
63
+ - lib/pgcrypto/key_manager.rb
64
+ - lib/pgcrypto/railtie.rb
65
+ - lib/pgcrypto/table.rb
83
66
  - lib/pgcrypto/table_manager.rb
67
+ - lib/tasks/pgcrypto.rake
84
68
  - pgcrypto.gemspec
85
69
  - spec/lib/pgcrypto_spec.rb
86
70
  - spec/spec_helper.rb
@@ -1,17 +0,0 @@
1
- class InstallPgcrypto < ActiveRecord::Migration
2
- def up
3
- create_table :pgcrypto_columns do |t|
4
- t.belongs_to :owner, :polymorphic => true
5
- t.string :owner_table, :limit => 32
6
- t.string :name, :limit => 32
7
- t.binary :value
8
- end
9
- add_index :pgcrypto_columns, [:owner_id, :owner_type, :name], :name => :pgcrypto_type_finder
10
- add_index :pgcrypto_columns, [:owner_id, :owner_table, :name], :name => :pgcrypto_table_finder
11
- execute("CREATE EXTENSION IF NOT EXISTS pgcrypto")
12
- end
13
-
14
- def down
15
- drop_table :pgcrypto_columns
16
- end
17
- end
@@ -1,88 +0,0 @@
1
- require 'active_record/connection_adapters/postgresql_adapter'
2
-
3
- ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
4
- unless instance_methods.include?(:to_sql_without_pgcrypto) || instance_methods.include?('to_sql_without_pgcrypto')
5
- alias :to_sql_without_pgcrypto :to_sql
6
- end
7
-
8
- def to_sql(arel, *args)
9
- case arel
10
- when Arel::InsertManager
11
- pgcrypto_tweak_insert(arel)
12
- when Arel::SelectManager
13
- pgcrypto_tweak_select(arel)
14
- when Arel::UpdateManager
15
- pgcrypto_tweak_update(arel)
16
- end
17
- to_sql_without_pgcrypto(arel, *args)
18
- end
19
-
20
- private
21
- def pgcrypto_tweak_insert(arel)
22
- if arel.ast.relation.name.to_s == PGCrypto::Column.table_name.to_s
23
- return unless key = PGCrypto.keys[:public]
24
- arel.ast.columns.each_with_index do |column, i|
25
- if column.name == 'value'
26
- value = arel.ast.values.expressions[i]
27
- quoted_value = quote_string(value)
28
- encryption_instruction = %[pgp_pub_encrypt(#{quoted_value}, #{key.dearmored})]
29
- arel.ast.values.expressions[i] = Arel::Nodes::SqlLiteral.new(encryption_instruction)
30
- end
31
- end
32
- end
33
- end
34
-
35
- def pgcrypto_tweak_select(arel)
36
- return unless key = PGCrypto.keys[:private]
37
- # We start by looping through each "core," which is just
38
- # a SelectStatement and correcting plain-text queries
39
- # against an encrypted column...
40
- joins = []
41
- table_name = nil
42
- arel.ast.cores.each do |core|
43
- # Yeah, I'm lazy. Whatevs.
44
- next unless core.is_a?(Arel::Nodes::SelectCore)
45
-
46
- encrypted_columns = PGCrypto[table_name = core.source.left.name]
47
- next if encrypted_columns.empty?
48
-
49
- # We loop through each WHERE specification to determine whether or not the
50
- # PGCrypto column should be JOIN'd upon; in which case, we, like, do it.
51
- core.wheres.each do |where|
52
- # Now loop through the children to encrypt them for the SELECT
53
- where.children.each do |child|
54
- next unless encrypted_columns[child.left.name.to_s]
55
- joins.push(child.left.name.to_s) unless joins.include?(child.left.name.to_s)
56
- child.left = Arel::Nodes::SqlLiteral.new(%[
57
- pgp_pub_decrypt("#{PGCrypto::Column.table_name}_#{child.left.name}"."value", pgcrypto_keys.#{key.name}#{key.password?})
58
- ])
59
- end if where.respond_to?(:children)
60
- end
61
- end
62
- if joins.any?
63
- arel.join(Arel::Nodes::SqlLiteral.new("CROSS JOIN (SELECT #{key.dearmored} AS #{key.name}) AS pgcrypto_keys"))
64
- joins.each do |column|
65
- column = quote_string(column)
66
- as_table = "#{PGCrypto::Column.table_name}_#{column}"
67
- arel.join(Arel::Nodes::SqlLiteral.new(%[
68
- JOIN "#{PGCrypto::Column.table_name}" AS "#{as_table}" ON "#{as_table}"."owner_id" = "#{table_name}"."id" AND "#{as_table}"."owner_table" = '#{quote_string(table_name)}' AND "#{as_table}"."name" = '#{column}'
69
- ]))
70
- end
71
- end
72
- end
73
-
74
- def pgcrypto_tweak_update(arel)
75
- if arel.ast.relation.name.to_s == PGCrypto::Column.table_name.to_s
76
- # Loop through the assignments and make sure we take care of that whole
77
- # NULL value thing!
78
- value = arel.ast.values.select{|value| value.respond_to?(:left) && value.left.name == 'value' }.first
79
- if value.right.nil?
80
- value.right = Arel::Nodes::SqlLiteral.new('NULL')
81
- elsif key = PGCrypto.keys[:public]
82
- quoted_right = quote_string(value.right)
83
- encryption_instruction = %[pgp_pub_encrypt('#{quoted_right}', #{key.dearmored})]
84
- value.right = Arel::Nodes::SqlLiteral.new(encryption_instruction)
85
- end
86
- end
87
- end
88
- end
@@ -1,24 +0,0 @@
1
- require 'arel/visitors/postgresql'
2
-
3
- # We override some fun stuff in the PostgreSQL visitor class inside of Arel.
4
- # This is the _most_ direct approach to tweaking the SQL to INSERT, SELECT,
5
- # and UPDATE values as encrypted. Unfortunately, the visitor API doesn't
6
- # give us access to managers as well as nodes, so we have use the public
7
- # Arel API via the connection adapter's to_sql method. Then we tweak the
8
- # more specific bits here!
9
-
10
- Arel::Visitors::PostgreSQL.class_eval do
11
- unless instance_methods.include?(:visit_Arel_Nodes_Assignment_without_pgcrypto) || instance_methods.include?('visit_Arel_Nodes_Assignment_without_pgcrypto')
12
- alias :visit_Arel_Nodes_Assignment_without_pgcrypto :visit_Arel_Nodes_Assignment
13
- end
14
-
15
- def visit_Arel_Nodes_Assignment(assignment)
16
- # Hijack the normally inoccuous assignment that happens, seeing as how
17
- # Arel normally forwards this shit to someone else and I hate it.
18
- if assignment.left.relation.name == PGCrypto::Column.table_name && assignment.left.name == 'value'
19
- "#{visit(assignment.left)} = #{visit(assignment.right)}"
20
- else
21
- visit_Arel_Nodes_Assignment_without_pgcrypto(assignment)
22
- end
23
- end
24
- end