stderr-sentry 0.5.4

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.
@@ -0,0 +1,17 @@
1
+ module Sentry
2
+ class SymmetricSentryCallback
3
+ def initialize(attr_name)
4
+ @attr_name = attr_name
5
+ end
6
+
7
+ # Performs encryption on before_validation Active Record callback
8
+ def before_validation(model)
9
+ return if model.send(@attr_name).blank?
10
+ model.send("crypted_#{@attr_name}=", SymmetricSentry.encrypt_to_base64(model.send(@attr_name)))
11
+ end
12
+
13
+ def after_save(model)
14
+ model.send("#{@attr_name}=", nil)
15
+ end
16
+ end
17
+ end
data/sentry.gemspec ADDED
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "stderr-sentry"
8
+ s.version = "0.5.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Josh Fenio"]
12
+ s.date = %q{2010-04-02}
13
+ s.description = %q{Asymmetric / Symmetric encryption of active record fields}
14
+ s.email = %q{stderr@truedat.org}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gemspec",
20
+ ".gitignore",
21
+ "CHANGELOG",
22
+ "MIT-LICENSE",
23
+ "README",
24
+ "RUNNING_UNIT_TESTS",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "init.rb",
28
+ "lib/active_record/sentry.rb",
29
+ "lib/sentry.rb",
30
+ "lib/sentry/asymmetric_sentry.rb",
31
+ "lib/sentry/asymmetric_sentry_callback.rb",
32
+ "lib/sentry/sha_sentry.rb",
33
+ "lib/sentry/symmetric_sentry.rb",
34
+ "lib/sentry/symmetric_sentry_callback.rb",
35
+ "sentry.gemspec",
36
+ "tasks/sentry.rake",
37
+ "test/abstract_unit.rb",
38
+ "test/asymmetric_sentry_callback_test.rb",
39
+ "test/asymmetric_sentry_test.rb",
40
+ "test/database.yml",
41
+ "test/fixtures/user.rb",
42
+ "test/fixtures/users.yml",
43
+ "test/keys/encrypted_private",
44
+ "test/keys/encrypted_public",
45
+ "test/keys/private",
46
+ "test/keys/public",
47
+ "test/rsa_key_test.rb",
48
+ "test/schema.rb",
49
+ "test/sha_sentry_test.rb",
50
+ "test/symmetric_sentry_callback_test.rb",
51
+ "test/symmetric_sentry_test.rb",
52
+ "test/tests.rb"
53
+ ]
54
+ s.homepage = %q{http://github.com/pivotal/sentry}
55
+ s.rdoc_options = ["--charset=UTF-8"]
56
+ s.require_paths = ["lib"]
57
+ s.rubygems_version = %q{1.3.5}
58
+ s.summary = %q{Asymmetric encryption of active record fields}
59
+ s.test_files = [
60
+ "test/abstract_unit.rb",
61
+ "test/asymmetric_sentry_callback_test.rb",
62
+ "test/asymmetric_sentry_test.rb",
63
+ "test/fixtures/user.rb",
64
+ "test/rsa_key_test.rb",
65
+ "test/schema.rb",
66
+ "test/sha_sentry_test.rb",
67
+ "test/symmetric_sentry_callback_test.rb",
68
+ "test/symmetric_sentry_test.rb",
69
+ "test/tests.rb"
70
+ ]
71
+
72
+ if s.respond_to? :specification_version then
73
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
74
+ s.specification_version = 3
75
+
76
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
77
+ else
78
+ end
79
+ else
80
+ end
81
+ end
82
+
data/tasks/sentry.rake ADDED
@@ -0,0 +1,9 @@
1
+ require 'sentry'
2
+
3
+ desc "Creates a private/public key for asymmetric encryption: rake sentry_key PUB=/path/to/public.key PRIV=/path/to/priv.key [KEY=secret]"
4
+ task :sentry_key do
5
+ Sentry::AsymmetricSentry.save_random_rsa_key(
6
+ ENV['PRIV'] || 'private.key',
7
+ ENV['PUB'] || 'public.key',
8
+ :key => ENV['KEY'])
9
+ end
@@ -0,0 +1,44 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'active_record'
6
+ require 'active_record/fixtures'
7
+ require 'active_support/test_case'
8
+ #require 'active_support/binding_of_caller'
9
+ #require 'active_support/breakpoint'
10
+ require "#{File.dirname(__FILE__)}/../lib/sentry"
11
+
12
+ config_location = File.dirname(__FILE__) + '/database.yml'
13
+
14
+ config = YAML::load(IO.read(config_location))
15
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
16
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'mysql'])
17
+ ActiveRecord::Base.configurations["test"] = "lolcatz"
18
+
19
+ load(File.dirname(__FILE__) + "/schema.rb")
20
+
21
+ class ActiveSupport::TestCase #:nodoc:
22
+ include ActiveRecord::TestFixtures
23
+ #def create_fixtures(*table_names)
24
+ # if block_given?
25
+ # Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, table_names) { yield }
26
+ # else
27
+ # Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, table_names)
28
+ # end
29
+ #end
30
+
31
+ self.use_instantiated_fixtures = false
32
+ self.use_transactional_fixtures = true
33
+ end
34
+
35
+ def create_fixtures(*table_names, &block)
36
+ Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, table_names, {}, &block)
37
+ end
38
+
39
+
40
+
41
+ ActiveSupport::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
42
+ ActiveSupport::TestCase.use_instantiated_fixtures = true
43
+ ActiveSupport::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")
44
+ $LOAD_PATH.unshift(ActiveSupport::TestCase.fixture_path)
@@ -0,0 +1,122 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/user'
3
+
4
+ class AsymmetricSentryCallbackTest < ActiveSupport::TestCase
5
+ fixtures :users
6
+
7
+ def setup
8
+ super
9
+ @str = 'sentry'
10
+ @key = 'secret'
11
+ @public_key_file = File.dirname(__FILE__) + '/keys/public'
12
+ @private_key_file = File.dirname(__FILE__) + '/keys/private'
13
+ @encrypted_public_key_file = File.dirname(__FILE__) + '/keys/encrypted_public'
14
+ @encrypted_private_key_file = File.dirname(__FILE__) + '/keys/encrypted_private'
15
+
16
+ @orig = 'sentry'
17
+ Sentry::AsymmetricSentry.default_public_key_file = @public_key_file
18
+ Sentry::AsymmetricSentry.default_private_key_file = @private_key_file
19
+ Sentry::SymmetricSentry.default_key = @key
20
+ end
21
+
22
+ def teardown
23
+ super
24
+ Sentry.default_key = nil
25
+ end
26
+
27
+ def test_encryption_should_use_default_key_when_present
28
+ use_encrypted_keys
29
+
30
+ assert_nil users(:user_2).creditcard
31
+ Sentry.default_key = @key
32
+
33
+ assert_equal @orig, users(:user_2).creditcard
34
+ end
35
+
36
+ def test_encrypt_for_sentry
37
+ assert_not_nil User.encrypt_for_sentry("hello")
38
+ end
39
+
40
+ def test_encryption_with_random_padding
41
+ # system works with unsaved record
42
+ u = User.new :login => 'jones'
43
+ u.creditcard = @orig
44
+ assert_equal @orig, u.creditcard
45
+ u.save!
46
+
47
+ # reload after save and check the decrypt works
48
+ u = User.find(u.id)
49
+ assert_equal @orig, u.creditcard
50
+ original_crypttext = u.crypted_creditcard
51
+
52
+ # set to same plaintext
53
+ u.creditcard = @orig
54
+ u.save!
55
+
56
+ # expect different crypttext (due to random padding)
57
+ assert_not_equal original_crypttext, u.crypted_creditcard
58
+ end
59
+
60
+ def test_should_handle_nils
61
+ u = User.create :login => 'john'
62
+ u.creditcard = nil
63
+ assert u.save
64
+ assert u.crypted_creditcard.nil?
65
+ assert u.creditcard.nil?
66
+ end
67
+
68
+ def test_should_encrypt_creditcard
69
+ u = User.create :login => 'jones'
70
+ u.creditcard = @orig
71
+ assert u.save
72
+ assert !u.crypted_creditcard.empty?
73
+ end
74
+
75
+ def test_should_deal_with_before_typecast
76
+ u = User.create :login => 'jones'
77
+ u.creditcard = "123123"
78
+ assert_equal "123123", u.creditcard_before_type_cast
79
+ assert u.save
80
+ u.reload
81
+ assert_equal "123123", u.creditcard_before_type_cast
82
+ end
83
+
84
+ def test_should_decrypt_creditcard
85
+ assert_equal @orig, users(:user_1).creditcard
86
+ end
87
+
88
+ def test_should_not_decrypt_encrypted_creditcard_with_invalid_key
89
+ assert_nil users(:user_2).creditcard
90
+ assert_nil users(:user_2).creditcard(@key)
91
+ use_encrypted_keys
92
+ assert_nil users(:user_1).creditcard
93
+ end
94
+
95
+ def test_should_not_decrypt_encrypted_creditcard
96
+ use_encrypted_keys
97
+ assert_nil users(:user_2).creditcard
98
+ assert_nil users(:user_2).creditcard('other secret')
99
+ end
100
+
101
+ def test_do_encryption
102
+ use_encrypted_keys
103
+ end
104
+
105
+ def test_should_encrypt_encrypted_creditcard
106
+ use_encrypted_keys
107
+ u = User.create :login => 'jones'
108
+ u.creditcard = @orig
109
+ assert u.save
110
+ assert !u.crypted_creditcard.empty?
111
+ end
112
+
113
+ def test_should_decrypt_encrypted_creditcard
114
+ use_encrypted_keys
115
+ assert_equal @orig, users(:user_2).creditcard(@key)
116
+ end
117
+
118
+ def use_encrypted_keys
119
+ Sentry::AsymmetricSentry.default_public_key_file = @encrypted_public_key_file
120
+ Sentry::AsymmetricSentry.default_private_key_file = @encrypted_private_key_file
121
+ end
122
+ end
@@ -0,0 +1,97 @@
1
+ require 'abstract_unit'
2
+
3
+ class AsymmetricSentryTest < Test::Unit::TestCase
4
+ def setup
5
+ Sentry::AsymmetricSentry.default_public_key_file = nil
6
+ Sentry::AsymmetricSentry.default_private_key_file = nil
7
+ @str = 'sentry'
8
+ @key = 'secret'
9
+ @public_key_file = File.dirname(__FILE__) + '/keys/public'
10
+ @private_key_file = File.dirname(__FILE__) + '/keys/private'
11
+ @encrypted_public_key_file = File.dirname(__FILE__) + '/keys/encrypted_public'
12
+ @encrypted_private_key_file = File.dirname(__FILE__) + '/keys/encrypted_private'
13
+ @sentry = Sentry::AsymmetricSentry.new
14
+
15
+ @orig = 'sentry'
16
+ @data = "vYfMxtVB8ezXmQKSNqTC9sPgi8TbsYRxWd7DVbpprzyuEdZ7gftJ/0IXsbXm\nXCU08bTAl0uEFm7dau+eJMXEJg==\n"
17
+ @encrypted_data = "q2obYAITmK93ylzVS01mJx1jSlnmylMX15nFpb4uKesVgnqvtzBRHZ/SK+Nm\nEzceIoAcJc3DHosVa4VUE/aK/A==\n"
18
+ end
19
+
20
+ def test_should_decrypt_files
21
+ set_key_files @public_key_file, @private_key_file
22
+ assert_equal @orig, @sentry.decrypt_from_base64(@data)
23
+ end
24
+
25
+ def test_should_decrypt_files_with_encrypted_key
26
+ set_key_files @encrypted_public_key_file, @encrypted_private_key_file
27
+ assert_equal @orig, @sentry.decrypt_from_base64(@encrypted_data, @key)
28
+ end
29
+
30
+ def test_should_read_key_files
31
+ assert !@sentry.public?
32
+ assert !@sentry.private?
33
+ set_key_files @public_key_file, @private_key_file
34
+ end
35
+
36
+ def test_should_read_encrypted_key_files
37
+ assert !@sentry.public?
38
+ assert !@sentry.private?
39
+ set_key_files @encrypted_public_key_file, @encrypted_private_key_file
40
+ end
41
+
42
+ def test_should_decrypt_files_with_default_key
43
+ set_default_key_files @public_key_file, @private_key_file
44
+ assert_equal @orig, @sentry.decrypt_from_base64(@data)
45
+ end
46
+
47
+ def test_should_decrypt_files_with_default_encrypted_key
48
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
49
+ assert_equal @orig, @sentry.decrypt_from_base64(@encrypted_data, @key)
50
+ end
51
+
52
+ def test_should_decrypt_block_by_block_for_large_data
53
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
54
+ large_data = "asdf" * 2048
55
+ encrypted = @sentry.encrypt_large_to_base64(large_data)
56
+ assert_not_equal large_data, encrypted
57
+ assert_equal large_data, @sentry.decrypt_large_from_base64(encrypted, @key)
58
+ end
59
+
60
+ def test_should_decrypt_files_with_default_key_using_class_method
61
+ set_default_key_files @public_key_file, @private_key_file
62
+ assert_equal @orig, Sentry::AsymmetricSentry.decrypt_from_base64(@data)
63
+ end
64
+
65
+ def test_should_decrypt_files_with_default_encrypted_key_using_class_method
66
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
67
+ assert_equal @orig, Sentry::AsymmetricSentry.decrypt_from_base64(@encrypted_data, @key)
68
+ end
69
+
70
+ def test_should_read_key_files_with_default_key
71
+ assert !@sentry.public?
72
+ assert !@sentry.private?
73
+ set_default_key_files @public_key_file, @private_key_file
74
+ end
75
+
76
+ def test_should_read_encrypted_key_files_with_default_key
77
+ assert !@sentry.public?
78
+ assert !@sentry.private?
79
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
80
+ end
81
+
82
+ private
83
+
84
+ def set_key_files(public_key, private_key)
85
+ @sentry.public_key_file = public_key
86
+ @sentry.private_key_file = private_key
87
+ assert @sentry.private?
88
+ assert @sentry.public?
89
+ end
90
+
91
+ def set_default_key_files(public_key, private_key)
92
+ Sentry::AsymmetricSentry.default_public_key_file = public_key
93
+ Sentry::AsymmetricSentry.default_private_key_file = private_key
94
+ assert @sentry.private?
95
+ assert @sentry.public?
96
+ end
97
+ end
data/test/database.yml ADDED
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: sentry_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: sentry_plugin.sqlite3.db
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: sentry_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: root
17
+ :password: password
18
+ :database: sentry_plugin_test
@@ -0,0 +1,26 @@
1
+ class User < ActiveRecord::Base
2
+ #define_read_methods
3
+ asymmetrically_encrypts :creditcard
4
+
5
+ #def self.validates_password
6
+ # validates_presence_of :password
7
+ # validates_presence_of :password, :on => :create
8
+ # validates_length_of :password, :in => 4..40
9
+ #end
10
+ end
11
+
12
+ #class ShaUser < User
13
+ # validates_password
14
+ # validates_confirmation_of :password
15
+ # generates_crypted :password # sha is used by default
16
+ #end
17
+ #
18
+ #class DangerousUser < User # no password confirmation
19
+ ## validates_password
20
+ # generates_crypted :password
21
+ #end
22
+ #
23
+ #class SymmetricUser < User
24
+ # validates_password
25
+ # generates_crypted :password, :mode => :symmetric
26
+ #end
@@ -0,0 +1,9 @@
1
+ user_1:
2
+ id: 1
3
+ login: bob
4
+ password: "0XlmUuNpE2k=\n"
5
+ creditcard: "CBUI2TcYh/ATRB7fYpDBb0t1ifOWPb5jfpO2M8Zy9D/8Gua6/uA+ILHwKtGY\nOgrooPYSxwpBzEZoH18mXqJE7yk=\n" # "sentry" with 8 characters of prepadding
6
+ user_2:
7
+ id: 2
8
+ login: fred
9
+ creditcard: "CEUx1Ufxi7leQVp0xHhMWKqBcvrb0p3VvX5rqJBXSwddH+Alscs73TEX8Ctn\n9WnV5Ii8txpa20UfM3h5msLpm20=\n" # "sentry" with 8 different characters of prepadding
@@ -0,0 +1,12 @@
1
+ OBNa1q8kbx8pyZZjIpr/pZV0oulE2czh5JlPW/13XsBvoz+A2zxA9gchhi6c
2
+ 3yvfqgcZdojcsep+IiTqeg3gOPB2xNbedpP1lm+9tEfgdb9r1CLzRcURh7Hg
3
+ ufWgyEkS0lloz/YLy4hg9YDKetFNF9fnrk3xVwZPwFVuk4l/Unw1FTXLHsrq
4
+ KG27cR8mvNOow4bk4LVhk/avFSM85m3ITySEnyJsQQDzsI/RrWcQ7Js+8Ynv
5
+ esN51E/T0CYtkMEne2zSaD5qUTJlQ7Qtn4UUeZkpYjn4xQZPxw4OjL6zofg7
6
+ lsqElSv1/qP3QI8aKcQQklVsHRc5AgsxOFX4J6g6lo4kOGOwn0Ex8IRDfOej
7
+ pq4SUDh9IXz+6FBieQrObB/xEsKysVwRSzXre6ObHlPFsigg5ekFPyCv5ZTz
8
+ 0iP8+xe/FJRrYdR3r3F5pRkOy0pw9EqlrLjmOx3/fgxhLq8FWmcSBbH3h3SG
9
+ GkJlfHNjF77FTJjnHKzRS+5VpdW4IHbsjL+NlI1z9Ol//czYvSGv85NdJvkq
10
+ PmH3o0+uYdwY5PeSMOPV21nJ3dwiKlm5IMFasL3C5yVJNVTVZTS7vWdcgZ4U
11
+ XfWQ9Y266ibbqXPluv4nxt1+kgjxmPbjPdYrlB5t7a2+unzT3oE3f4VGOG+k
12
+ YqFg0ErHN+fu