pgcrypto 0.1.0 → 0.1.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.
data/.rspec CHANGED
@@ -1 +1,3 @@
1
+ --backtrace
1
2
  --colour
3
+ --format Fuubar
data/.simplecov ADDED
@@ -0,0 +1,4 @@
1
+ SimpleCov.start do
2
+ add_filter "test.rb"
3
+ add_filter "/spec/"
4
+ end
data/CHANGES CHANGED
@@ -1,3 +1,8 @@
1
+ 0.1.1
2
+ * Rebuilt the WHERE clause stuff to make sure finders AND setters
3
+ both worked. It's fragile and hackish at this time, but we'll get
4
+ there, folks!
5
+
1
6
  0.1.0
2
7
  * Overhauled the underpinnings to rely on a separate column. Adds
3
8
  on-demand loading of encrypted attributes from a central table
data/Gemfile CHANGED
@@ -1 +1,16 @@
1
- gem 'activerecord', '>= 3.2'
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'activerecord', '>= 3.2', :require => 'active_record'
4
+
5
+ group :test do
6
+ gem 'autotest'
7
+ gem 'database_cleaner', '>= 0.7'
8
+ gem 'fuubar'
9
+ gem 'pg', '>= 0.11'
10
+ gem 'rspec', rspec_version = '>= 2.6'
11
+ gem 'simplecov', :require => false
12
+ if RUBY_PLATFORM =~ /darwin/
13
+ gem 'autotest-fsevent', '>= 0.2'
14
+ gem 'autotest-growl', '>= 0.2'
15
+ end
16
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
@@ -0,0 +1,14 @@
1
+ require 'autotest/fsevent'
2
+ require 'autotest/growl'
3
+
4
+ Autotest.add_discovery { "rspec2" }
5
+
6
+ Autotest.add_hook :initialize do |autotest|
7
+ autotest.add_mapping %r(^lib/**/*\.rb$) do |file, _|
8
+ Dir['spec/**/*.rb']
9
+ end
10
+
11
+ autotest.add_mapping %r(^spec/support/*\.rb$) do |file, _|
12
+ Dir['spec/**/*.rb']
13
+ end
14
+ end
@@ -2,7 +2,8 @@ class InstallPgcrypto < ActiveRecord::Migration
2
2
  def up
3
3
  create_table :pgcrypto_columns do |t|
4
4
  t.belongs_to :owner, :polymorphic => true
5
- t.string :name, :limit => 64
5
+ t.string :owner_table, :limit => 32
6
+ t.string :name, :limit => 32
6
7
  t.binary :value
7
8
  end
8
9
  add_index :pgcrypto_columns, [:owner_id, :owner_type, :name], :name => :pgcrypto_column_finder
@@ -9,6 +9,8 @@ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
9
9
  case arel
10
10
  when Arel::InsertManager
11
11
  pgcrypto_tweak_insert(arel, *args)
12
+ when Arel::SelectManager
13
+ pgcrypto_tweak_select(arel)
12
14
  when Arel::UpdateManager
13
15
  pgcrypto_tweak_update(arel)
14
16
  end
@@ -35,6 +37,47 @@ ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
35
37
  end
36
38
  end
37
39
 
40
+ def pgcrypto_tweak_select(arel)
41
+ # We start by looping through each "core," which is just
42
+ # a SelectStatement and correcting plain-text queries
43
+ # against an encrypted column...
44
+ joins = {}
45
+ table_name = nil
46
+ arel.ast.cores.each do |core|
47
+ # Yeah, I'm lazy. Whatevs.
48
+ next unless core.is_a?(Arel::Nodes::SelectCore) && !(columns = PGCrypto[table_name = core.source.left.name]).empty?
49
+
50
+ # We loop through each WHERE specification to determine whether or not the
51
+ # PGCrypto column should be JOIN'd upon; in which case, we, like, do it.
52
+ core.wheres.each do |where|
53
+ # Now loop through the children to encrypt them for the SELECT
54
+ where.children.each do |child|
55
+ if options = columns[child.left.name]
56
+ if key = PGCrypto.keys[options[:private_key] || :private]
57
+ join_name = "pgcrypto_column_#{child.left.name}"
58
+ joins[join_name] ||= {:column => child.left.name, :key => "#{key.dearmored} AS #{key.name}_key"}
59
+ child.left = Arel::Nodes::SqlLiteral.new(%[pgp_pub_decrypt("#{join_name}"."value", keys.#{key.name}_key)])
60
+ end
61
+ end
62
+ end if where.respond_to?(:children)
63
+ end
64
+ end
65
+ unless joins.empty?
66
+ key_joins = []
67
+ joins.each do |key_name, join|
68
+ key_joins.push(join[:key])
69
+ column = quote_string(join[:column].to_s)
70
+ arel.join(Arel::Nodes::SqlLiteral.new(%[
71
+ JOIN "pgcrypto_columns" AS "pgcrypto_column_#{column}" ON
72
+ "pgcrypto_column_#{column}"."owner_id" = "#{table_name}"."id"
73
+ AND "pgcrypto_column_#{column}"."owner_table" = '#{quote_string(table_name)}'
74
+ AND "pgcrypto_column_#{column}"."name" = '#{column}'
75
+ ]))
76
+ end
77
+ arel.join(Arel::Nodes::SqlLiteral.new("CROSS JOIN (SELECT #{key_joins.join(', ')}) AS keys"))
78
+ end
79
+ end
80
+
38
81
  def pgcrypto_tweak_update(arel)
39
82
  if arel.ast.relation.name == PGCrypto::Column.table_name
40
83
  # Loop through the assignments and make sure we take care of that whole
@@ -1,6 +1,12 @@
1
1
  module PGCrypto
2
2
  class Column < ActiveRecord::Base
3
3
  self.table_name = 'pgcrypto_columns'
4
+ before_save :set_owner_table
4
5
  belongs_to :owner, :autosave => false, :inverse_of => :pgcrypto_columns, :polymorphic => true
6
+
7
+ protected
8
+ def set_owner_table
9
+ self.owner_table = self.owner.class.table_name
10
+ end
5
11
  end
6
12
  end
data/lib/pgcrypto/key.rb CHANGED
@@ -24,7 +24,7 @@ module PGCrypto
24
24
 
25
25
  def initialize(options = {})
26
26
  if options.is_a?(String)
27
- self.value = key
27
+ self.value = options
28
28
  elsif options.is_a?(Hash)
29
29
  options.each do |key, value|
30
30
  send("#{key}=", value)
@@ -34,7 +34,7 @@ module PGCrypto
34
34
 
35
35
  def path=(keyfile)
36
36
  keyfile = File.expand_path(keyfile)
37
- raise PGCrypto::Error, "\#{keyfile} does not exist!" unless File.file?(keyfile)
37
+ raise PGCrypto::Error, "#{keyfile} does not exist!" unless File.file?(keyfile)
38
38
  @path = keyfile
39
39
  self.value = File.read(keyfile)
40
40
  end
data/pgcrypto.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pgcrypto"
8
- s.version = "0.1.0"
8
+ s.version = "0.1.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Flip Sasser"]
@@ -18,12 +18,14 @@ Gem::Specification.new do |s|
18
18
  ]
19
19
  s.files = [
20
20
  ".rspec",
21
+ ".simplecov",
21
22
  "CHANGES",
22
23
  "Gemfile",
23
24
  "LICENSE",
24
25
  "README.markdown",
25
26
  "Rakefile",
26
27
  "VERSION",
28
+ "autotest/discover.rb",
27
29
  "lib/generators/pgcrypto/install/USAGE",
28
30
  "lib/generators/pgcrypto/install/install_generator.rb",
29
31
  "lib/generators/pgcrypto/install/templates/initializer.rb",
@@ -34,7 +36,11 @@ Gem::Specification.new do |s|
34
36
  "lib/pgcrypto/column.rb",
35
37
  "lib/pgcrypto/key.rb",
36
38
  "lib/pgcrypto/table_manager.rb",
37
- "pgcrypto.gemspec"
39
+ "pgcrypto.gemspec",
40
+ "spec/lib/pgcrypto_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "spec/support/private.key",
43
+ "spec/support/public.key"
38
44
  ]
39
45
  s.homepage = "http://github.com/Plinq/pgcrypto"
40
46
  s.require_paths = ["lib"]
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe PGCrypto do
4
+ it "should extend ActiveRecord::Base" do
5
+ PGCryptoTestModel.should respond_to(:pgcrypto)
6
+ end
7
+
8
+ describe "attributes" do
9
+ before :each do
10
+ PGCryptoTestModel.pgcrypto :test_column
11
+ end
12
+
13
+ it "should have readers and writers" do
14
+ model = PGCryptoTestModel.new
15
+ model.should respond_to(:test_column)
16
+ model.should respond_to(:test_column=)
17
+ end
18
+
19
+ it "be settable on create" do
20
+ model = PGCryptoTestModel.new(:test_column => 'this is a test')
21
+ model.save!.should be_true
22
+ end
23
+
24
+ it "be settable on update" do
25
+ model = PGCryptoTestModel.create!
26
+ model.test_column = 'this is another test'
27
+ model.save!.should be_true
28
+ end
29
+
30
+ it "be update-able" do
31
+ model = PGCryptoTestModel.create!(:test_column => 'i am test column')
32
+ model.update_attributes!(:test_column => 'but now i am a different column, son').should be_true
33
+ end
34
+
35
+ it "be retrievable at create" do
36
+ model = PGCryptoTestModel.create!(:test_column => 'i am test column')
37
+ model.test_column.should == 'i am test column'
38
+ end
39
+
40
+ it "be retrievable after create" do
41
+ model = PGCryptoTestModel.create!(:test_column => 'i should return to you')
42
+ PGCryptoTestModel.find(model.id).test_column.should == 'i should return to you'
43
+ end
44
+
45
+ it "be searchable" do
46
+ model = PGCryptoTestModel.create!(:test_column => 'i am findable!')
47
+ PGCryptoTestModel.where(:test_column => model.test_column).count.should == 1
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,79 @@
1
+ # Add lib/ to the load path
2
+ $LOAD_PATH.unshift(File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__)))
3
+
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'
11
+
12
+ # Requier and configure PGCrypto
13
+ require 'pgcrypto'
14
+ PGCrypto.keys[:private] = {:path => File.join(File.dirname(__FILE__), 'support', 'private.key')}
15
+ PGCrypto.keys[:public] = {:path => File.join(File.dirname(__FILE__), 'support', 'public.key')}
16
+
17
+ RSpec.configure do |config|
18
+ database_config = {:adapter => 'postgresql', :database => 'pgcrypto_test', :encoding => 'utf8', :host => 'localhost'}
19
+ postgres_config = database_config.merge(:database => 'postgres', :schema_search_path => 'public')
20
+
21
+ # Set up the database to handle pgcrypto functions and the schema for
22
+ # our tests
23
+ config.before :all do
24
+ # Connect to the local postgres schema database
25
+ ActiveRecord::Base.establish_connection(postgres_config)
26
+
27
+ # Create the test database if we can
28
+ ActiveRecord::Base.connection.create_database(database_config[:database]) rescue nil
29
+
30
+ # Now connect to the newly created database
31
+ ActiveRecord::Base.establish_connection(database_config)
32
+
33
+
34
+ silence_stream(STDOUT) do
35
+ # ...and load in the pgcrypto extension
36
+ ActiveRecord::Base.connection.execute(%[CREATE EXTENSION pgcrypto])
37
+
38
+ # ...and then set up the pgcrypto_columns and pgcrypto_test_models fun
39
+ ActiveRecord::Schema.define do
40
+ create_table :pgcrypto_columns, :force => true do |t|
41
+ t.belongs_to :owner, :polymorphic => true
42
+ t.string :owner_table, :limit => 32
43
+ t.string :name, :limit => 64
44
+ t.binary :value
45
+ end
46
+
47
+ create_table :pgcrypto_test_models, :force => true do |t|
48
+ t.string :name, :limit => 32
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ config.before :each do
55
+ if example.metadata[:transaction] == false
56
+ DatabaseCleaner.strategy = :truncation
57
+ DatabaseCleaner.clean_with :truncation
58
+ else
59
+ DatabaseCleaner.strategy = :transaction
60
+ end
61
+ DatabaseCleaner.start
62
+
63
+ ActiveRecord::Base.establish_connection(database_config)
64
+
65
+ class PGCryptoTestModel < ActiveRecord::Base
66
+ self.table_name = :pgcrypto_test_models
67
+ end
68
+ end
69
+
70
+ config.after :all do
71
+ # Drop the database when we exist
72
+ ActiveRecord::Base.establish_connection(postgres_config)
73
+ ActiveRecord::Base.connection.drop_database(database_config[:database]) rescue nil
74
+ end
75
+
76
+ config.after :each do
77
+ DatabaseCleaner.clean
78
+ end
79
+ end
@@ -0,0 +1,34 @@
1
+ -----BEGIN PGP PRIVATE KEY BLOCK-----
2
+ Version: GnuPG v1.4.12 (Darwin)
3
+
4
+ lQHYBE9ydVABBADfTmLU+G19Vz8iugTZfuxYG2KWI5+UEvW0APE0XF9R9bRca84m
5
+ +TbMmhs0hHWvH+5xmPgBN8atx1PAJj65LZufLQipXb4ZLYOi2OWPh7umlMaoSrwY
6
+ UI7SHxL/zqRkdwHiricxTlfqv4lPc7kxDjwfked8nDWcVkCreZVLTwwUfwARAQAB
7
+ AAP6Ay+UG2O79CjVfsJWpV+5MXyaiHfTpAItPTcyOcQDnCC8RQFIvKebj4m3T6WA
8
+ JFJ5TWeYSjQognwwhrJE/NFYwgLH698fEw3TEHyvXm6hdb3Aqv7wCc52pZx9E3OL
9
+ AvSQArTypTO4WsGsYIBVbpvsQervA03gxEo025q7QGPQYoECAOcC9eTlKznjDj09
10
+ 5AOueWE1s3NZDlESGkq6qEM+xIHurEvgX7jHLe0bRQWfo/Z/D5uplTrFkPTgtA/a
11
+ lwKej78CAPd2DYocgmCQ44e1Dc8Z8XSeKuMmmZqbFszDr8+4LM40irmFeiSb1S6p
12
+ rj1h2WKFhnar568tMSvxrZmu5dZ7q0EB/1kVXLAJK6PS7IhOnFMbMMQcWmQLfQ7I
13
+ pgEuUF6DG9drSbj8r5oU+PUejGmurl5ZqVWbCGHnlbTU/QsRhp8VvdegMLQ0Rmxp
14
+ cCBTYXNzZXIgKERlbGlnaHRmdWwgV2lkZ2V0cykgPGZsaXBAZ2V0cGxpbnEuY29t
15
+ Poi4BBMBAgAiBQJPcnVQAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBI
16
+ 6kAcpRMrn741BACT09j5TEG7YnjFf9eoXfh5JpYWv+xdnAJZjMdl+cMZ5CxZB+vx
17
+ zNhOX2OwCWu5fEh2wKbbRuLWHna6SebRjFzY62Ld0ijqVyRPzvz/v7Vn8pBqsTvJ
18
+ PgXUmrMmK9OAMAAM64NwRPiAxSkQtc3qG2uacDyCEI10uK9MT/zNmC6ISJ0B2ARP
19
+ cnVQAQQA9MEq2zMJtfWLZ2HfkTYkHemesc4XB+xCLfldNdmUwQ4o+GXfxe6VXYCc
20
+ KPpyx+qXSP6q7OxR8QKk8wbIord2/w6iIkn+ULvHQw1KMaCQW3JuQPB+IMWA3kY8
21
+ eQ3uibc2vk3ZFMtlU9HCxcRBPnMsCaBXYH1EkQ0+JVyuAotFOksAEQEAAQAD+gJY
22
+ HhfdLGDv4G08KXIdTlZANRMBGGss6GtcgcSKXqh3540nG9Z4+2xBI/3Br4fzp43j
23
+ ub5gLkUixqXfPdyB6Yokc+U0AQVuKZPXbFAROigD2gzpnDWaLeByL4Ua6FV6zNsl
24
+ gTLIS++r81KJBkiw0yhgqfNt44Gbta7y6nPXdMGRAgD1j+wyfvrhoAGgNkZR1h6U
25
+ A+enlaK5+TdeDFljJKo8w3io/s9abOLnVBE4rRsdZtJmK5q0rjeMNKzOsohk9EHR
26
+ AgD/KHTbvTsvrH6kcKpdCHGjyEnYAndxVbjoclHR7NRz6QlhqdNKGI0FbwmPcf7p
27
+ WOSXJX6j8u4dHrx1wZTcDMVbAf9/VsMOkzYnSQEzDV2ixunvkYmfNuD1NbYERgyG
28
+ 4Zd+TWKLPx98y/+VW8js5FkH46XgoOsYkEGjl3ZJb5kPth1rog2InwQYAQIACQUC
29
+ T3J1UAIbDAAKCRBI6kAcpRMrn/w6BADN0x89vP0LGRpnwK2Z8AVIXilcPNxe8ckq
30
+ xx0XIU5X13d6DtvNClhIu2N2fA0M2/PR7/MG8+zGoZLZUvC0D+WUNq3Y5hQb2K7J
31
+ IAVPNYVH+R05/1tWGsH/8h/eH9PvldQ8tjQV4jgLJqx5/PNrSb6WdSUmoKQrgORB
32
+ QNXpHhBr6g==
33
+ =sN2M
34
+ -----END PGP PRIVATE KEY BLOCK-----
@@ -0,0 +1,20 @@
1
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
2
+ Version: GnuPG v1.4.12 (Darwin)
3
+
4
+ mI0ET3J1UAEEAN9OYtT4bX1XPyK6BNl+7FgbYpYjn5QS9bQA8TRcX1H1tFxrzib5
5
+ NsyaGzSEda8f7nGY+AE3xq3HU8AmPrktm58tCKldvhktg6LY5Y+Hu6aUxqhKvBhQ
6
+ jtIfEv/OpGR3AeKuJzFOV+q/iU9zuTEOPB+R53ycNZxWQKt5lUtPDBR/ABEBAAG0
7
+ NEZsaXAgU2Fzc2VyIChEZWxpZ2h0ZnVsIFdpZGdldHMpIDxmbGlwQGdldHBsaW5x
8
+ LmNvbT6IuAQTAQIAIgUCT3J1UAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
9
+ CgkQSOpAHKUTK5++NQQAk9PY+UxBu2J4xX/XqF34eSaWFr/sXZwCWYzHZfnDGeQs
10
+ WQfr8czYTl9jsAlruXxIdsCm20bi1h52uknm0Yxc2Oti3dIo6lckT878/7+1Z/KQ
11
+ arE7yT4F1JqzJivTgDAADOuDcET4gMUpELXN6htrmnA8ghCNdLivTE/8zZguiEi4
12
+ jQRPcnVQAQQA9MEq2zMJtfWLZ2HfkTYkHemesc4XB+xCLfldNdmUwQ4o+GXfxe6V
13
+ XYCcKPpyx+qXSP6q7OxR8QKk8wbIord2/w6iIkn+ULvHQw1KMaCQW3JuQPB+IMWA
14
+ 3kY8eQ3uibc2vk3ZFMtlU9HCxcRBPnMsCaBXYH1EkQ0+JVyuAotFOksAEQEAAYif
15
+ BBgBAgAJBQJPcnVQAhsMAAoJEEjqQBylEyuf/DoEAM3THz28/QsZGmfArZnwBUhe
16
+ KVw83F7xySrHHRchTlfXd3oO280KWEi7Y3Z8DQzb89Hv8wbz7MahktlS8LQP5ZQ2
17
+ rdjmFBvYrskgBU81hUf5HTn/W1Yawf/yH94f0++V1Dy2NBXiOAsmrHn882tJvpZ1
18
+ JSagpCuA5EFA1ekeEGvq
19
+ =XKvD
20
+ -----END PGP PUBLIC KEY BLOCK-----
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pgcrypto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-03-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &70130059262260 !ruby/object:Gem::Requirement
16
+ requirement: &70275631246800 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '3.2'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70130059262260
24
+ version_requirements: *70275631246800
25
25
  description: ! "\n PGCrypto is an ActiveRecord::Base extension that allows you
26
26
  to asymmetrically\n encrypt PostgreSQL columns with as little trouble as possible.
27
27
  It's totally\n freaking rad.\n "
@@ -33,12 +33,14 @@ extra_rdoc_files:
33
33
  - README.markdown
34
34
  files:
35
35
  - .rspec
36
+ - .simplecov
36
37
  - CHANGES
37
38
  - Gemfile
38
39
  - LICENSE
39
40
  - README.markdown
40
41
  - Rakefile
41
42
  - VERSION
43
+ - autotest/discover.rb
42
44
  - lib/generators/pgcrypto/install/USAGE
43
45
  - lib/generators/pgcrypto/install/install_generator.rb
44
46
  - lib/generators/pgcrypto/install/templates/initializer.rb
@@ -50,6 +52,10 @@ files:
50
52
  - lib/pgcrypto/key.rb
51
53
  - lib/pgcrypto/table_manager.rb
52
54
  - pgcrypto.gemspec
55
+ - spec/lib/pgcrypto_spec.rb
56
+ - spec/spec_helper.rb
57
+ - spec/support/private.key
58
+ - spec/support/public.key
53
59
  homepage: http://github.com/Plinq/pgcrypto
54
60
  licenses: []
55
61
  post_install_message: