sentry 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +45 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README +80 -0
  4. data/RUNNING_UNIT_TESTS +41 -0
  5. data/lib/active_record/sentry.rb +79 -0
  6. data/lib/sentry.rb +46 -0
  7. data/lib/sentry/asymmetric_sentry.rb +144 -0
  8. data/lib/sentry/asymmetric_sentry_callback.rb +17 -0
  9. data/lib/sentry/sha_sentry.rb +41 -0
  10. data/lib/sentry/symmetric_sentry.rb +79 -0
  11. data/lib/sentry/symmetric_sentry_callback.rb +17 -0
  12. data/test/abstract_unit.rb +25 -0
  13. data/test/asymmetric_sentry_callback_test.rb +61 -0
  14. data/test/asymmetric_sentry_test.rb +88 -0
  15. data/test/connections/native_db2/connection.rb +14 -0
  16. data/test/connections/native_mysql/connection.rb +14 -0
  17. data/test/connections/native_oci/connection.rb +15 -0
  18. data/test/connections/native_postgresql/connection.rb +14 -0
  19. data/test/connections/native_sqlite/connection.rb +34 -0
  20. data/test/connections/native_sqlite3/connection.rb +33 -0
  21. data/test/connections/native_sqlserver/connection.rb +14 -0
  22. data/test/connections/native_sqlserver_odbc/connection.rb +15 -0
  23. data/test/fixtures/activerecord_sentry.sqlite +0 -0
  24. data/test/fixtures/activerecord_sentry.sqlite3 +0 -0
  25. data/test/fixtures/db_definitions/postgresql.drop.sql +1 -0
  26. data/test/fixtures/db_definitions/postgresql.sql +8 -0
  27. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  28. data/test/fixtures/db_definitions/sqlite.sql +7 -0
  29. data/test/fixtures/user.rb +25 -0
  30. data/test/fixtures/users.yml +11 -0
  31. data/test/keys/encrypted_private +12 -0
  32. data/test/keys/encrypted_public +4 -0
  33. data/test/keys/private +9 -0
  34. data/test/keys/public +4 -0
  35. data/test/sha_sentry_test.rb +31 -0
  36. data/test/symmetric_sentry_callback_test.rb +33 -0
  37. data/test/symmetric_sentry_test.rb +37 -0
  38. data/test/tests.rb +2 -0
  39. metadata +89 -0
@@ -0,0 +1,45 @@
1
+ *0.2.8* (17 Sep 2005)
2
+
3
+ * Added Active Record unit tests
4
+
5
+ *0.2.7* (17 Sep 2005)
6
+
7
+ * Added rdocs and stubs for AR unit tests
8
+
9
+ *0.2.6* (2 Aug 2005)
10
+
11
+ * Fixed generates_crypted so it adds attribute accessors
12
+
13
+ *0.2.5* (27 Jul 2005)
14
+
15
+ * Set ActiveRecord callback objects to only encrypt fields when they are not empty.
16
+
17
+ *0.2.4* (11 Jul 2005)
18
+
19
+ * Split ActiveRecord callback methods into their own classes.
20
+ * Set AR virtual columns to fail silently on errors.
21
+
22
+ *0.2.3* (11 Jul 2005)
23
+
24
+ * Added ActiveRecord callback objects for SymmetricSentry and AsymmetricSentry. +one_way_encrypt+ is depreciated.
25
+ * Readme doc added too
26
+
27
+ *0.2.1* (9 Jul 2005)
28
+
29
+ * vastly simplified one_way_encrypt at danp's suggestion. Use this in your model to try it out:
30
+
31
+ +one_way_encrypt :password*
32
+
33
+ That generates an SHA hash of model.password to model.crypted_password which is saved in the DB.
34
+ model.password is a virtual field. Continue using validates_confirmation_of for confirmation.
35
+
36
+
37
+ *0.2* (9 Jul 2005)
38
+
39
+ * added ActiveRecord::Base#one_way_encrypt class method to hash passwords with SHA
40
+ * Renamed core classes to SymmetricSentry and AsymmetricSentry
41
+ * Test Suite added
42
+
43
+ *0.1*
44
+
45
+ * Initial Import
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2005 Rick Olson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,80 @@
1
+ = Sentry lib - painless encryption library
2
+
3
+ Sentry is a simple wrapper around the mostly undocumented OpenSSL encryption classes.
4
+ For now, look at the pseudo test cases in sentry.rb until I can get more examples written out.
5
+
6
+ == Download
7
+
8
+ Sentry is distributed as a gem:
9
+
10
+ gem install --source http://techno-weenie.net/code sentry
11
+
12
+ Please email any comments or changes for code to technoweenie AT gmail.com
13
+
14
+ == Using with ActiveRecord
15
+
16
+ I wrote this for the purpose of encrypting ActiveRecord attributes. Just <tt>require 'sentry'</tt>, and some new
17
+ class methods will be available to you:
18
+
19
+ === generates_crypted
20
+
21
+ generates_crypted :password, :mode => :sha | :symmetric | :asymmetric
22
+
23
+ This is the generic class method to use. Default mode is :sha.
24
+
25
+ === generates_crypted_hash_of
26
+
27
+ generates_crypted_hash_of :password
28
+
29
+ This is a shortcut for using SHA encryption. No different than specifying <tt>generates_crypted :password</tt>. In the above
30
+ example, model.password is a virtual field, and the SHA hash is saved to model.crypted_password
31
+
32
+ === asymmetrically_encrypts
33
+
34
+ asymmetrically_encrypts :password
35
+
36
+ This is a shortcut for using an asymmetrical algorithm with a private/public key file. To use this, generate a public and
37
+ private key with Sentry::AsymmetricalSentry.save_random_rsa_key(private_key_file, public_key_file). If you want to encrypt the
38
+ private key file with a symmetrical algorithm, pass a secret key (neither the key nor the decrypted value will be stored).
39
+
40
+ Sentry::AsymmetricalSentry.save_random_rsa_key(private_key_file, public_key_file, :key => 'secret_password')
41
+
42
+ What that does, is requires you to pass in that same secret password when accesing the method.
43
+
44
+ class Model < ActiveRecord::Base
45
+ generates_crypted :password, :mode => :asymmetric
46
+ end
47
+
48
+ model.password = '5234523453425'
49
+ model.save # password is encrypted and saved to crypted_password in the database,
50
+ # model.password is cleared and becomes a virtual field.
51
+ model.password('secret_password')
52
+ => '5234523453425'
53
+
54
+ The public and private key file names can be set in config/environment.rb
55
+
56
+ Sentry::AsymmetricSentry.default_public_key_file = "#{RAILS_ROOT}/config/public.key"
57
+ Sentry::AsymmetricSentry.default_private_key_file = "#{RAILS_ROOT}/config/private.key"
58
+
59
+ If the private key was encrypted with the Sentry::AsymmetricalSentry#save_random_rsa_key, you must provide that same key
60
+ when accessing the AR model.
61
+
62
+ === symmetrically_encrypts
63
+
64
+ symmetrically_encrypts :password
65
+
66
+ This is a shortcut for using a symmetrical algorithm with a secret password to encrypt the field.
67
+
68
+ class Model < ActiveRecord::Base
69
+ generates_crypted :password, :mode => :symmetric
70
+ end
71
+
72
+ model.password = '5234523453425'
73
+ model.save # password is encrypted and saved to crypted_password in the database,
74
+ # model.password is cleared and becomes a virtual field.
75
+ model.password
76
+ => '5234523453425'
77
+
78
+ The secret password can be set in config/environment.rb
79
+
80
+ Sentry::SymmetricSentry.default_key = "secret_password"
@@ -0,0 +1,41 @@
1
+ == Creating the test database
2
+
3
+ The default name for the test databases is "activerecord_sentry". If you
4
+ want to use another database name then be sure to update the connection
5
+ adapter setups you want to test with in test/connections/<your database>/connection.rb.
6
+ When you have the database online, you can import the fixture tables with
7
+ the test/fixtures/db_definitions/*.sql files.
8
+
9
+ Make sure that you create database objects with the same user that you specified in i
10
+ connection.rb otherwise (on Postgres, at least) tests for default values will fail.
11
+
12
+ == Running with Rake
13
+
14
+ The easiest way to run the unit tests is through Rake. The default task runs
15
+ the entire test suite for all the adapters. You can also run the suite on just
16
+ one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite,
17
+ or test_postresql. For more information, checkout the full array of rake tasks with "rake -T"
18
+
19
+ Rake can be found at http://rake.rubyforge.org
20
+
21
+ == Running by hand
22
+
23
+ Unit tests are located in test directory. If you only want to run a single test suite,
24
+ or don't want to bother with Rake, you can do so with something like:
25
+
26
+ cd test; ruby -I "connections/native_mysql" base_test.rb
27
+
28
+ That'll run the base suite using the MySQL-Ruby adapter. Change the adapter
29
+ and test suite name as needed.
30
+
31
+ == Faster tests
32
+
33
+ If you are using a database that supports transactions, you can set the
34
+ "AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures.
35
+ This gives a very large speed boost. With rake:
36
+
37
+ rake AR_TX_FIXTURES=yes
38
+
39
+ Or, by hand:
40
+
41
+ AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb
@@ -0,0 +1,79 @@
1
+ module ActiveRecord # :nodoc:
2
+ module Sentry
3
+ def self.included(base) # :nodoc:
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def generates_crypted(attr_name, options = {})
9
+ mode = options[:mode] || :sha
10
+ case mode
11
+ when :sha
12
+ generates_crypted_hash_of(attr_name)
13
+ when :asymmetric, :asymmetrical
14
+ asymmetrically_encrypts(attr_name)
15
+ when :symmetric, :symmetrical
16
+ symmetrically_encrypts(attr_name)
17
+ end
18
+ end
19
+
20
+ def generates_crypted_hash_of(attribute)
21
+ before_validation ::Sentry::ShaSentry.new(attribute)
22
+ attr_accessor attribute
23
+ end
24
+
25
+ def asymmetrically_encrypts(attr_name)
26
+ temp_sentry = ::Sentry::AsymmetricSentryCallback.new(attr_name)
27
+ before_validation temp_sentry
28
+ after_save temp_sentry
29
+
30
+ define_method(attr_name) do |*optional|
31
+ send("#{attr_name}!", *optional) rescue nil
32
+ end
33
+
34
+ define_method("#{attr_name}!") do |*optional|
35
+ return decrypted_values[attr_name] unless decrypted_values[attr_name].nil?
36
+ return nil if send("crypted_#{attr_name}").nil?
37
+ key = optional.shift
38
+ ::Sentry::AsymmetricSentry.decrypt_from_base64(send("crypted_#{attr_name}"), key)
39
+ end
40
+
41
+ define_method("#{attr_name}=") do |value|
42
+ decrypted_values[attr_name] = value
43
+ nil
44
+ end
45
+
46
+ private
47
+ define_method(:decrypted_values) do
48
+ @decrypted_values ||= {}
49
+ end
50
+ end
51
+
52
+ def symmetrically_encrypts(attr_name)
53
+ temp_sentry = ::Sentry::SymmetricSentryCallback.new(attr_name)
54
+ before_validation temp_sentry
55
+ after_save temp_sentry
56
+
57
+ define_method(attr_name) do
58
+ send("#{attr_name}!") rescue nil
59
+ end
60
+
61
+ define_method("#{attr_name}!") do
62
+ return decrypted_values[attr_name] unless decrypted_values[attr_name].nil?
63
+ return nil if send("crypted_#{attr_name}").nil?
64
+ ::Sentry::SymmetricSentry.decrypt_from_base64(send("crypted_#{attr_name}"))
65
+ end
66
+
67
+ define_method("#{attr_name}=") do |value|
68
+ decrypted_values[attr_name] = value
69
+ nil
70
+ end
71
+
72
+ private
73
+ define_method(:decrypted_values) do
74
+ @decrypted_values ||= {}
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,46 @@
1
+ #Copyright (c) 2005 Rick Olson
2
+ #
3
+ #Permission is hereby granted, free of charge, to any person obtaining
4
+ #a copy of this software and associated documentation files (the
5
+ #"Software"), to deal in the Software without restriction, including
6
+ #without limitation the rights to use, copy, modify, merge, publish,
7
+ #distribute, sublicense, and/or sell copies of the Software, and to
8
+ #permit persons to whom the Software is furnished to do so, subject to
9
+ #the following conditions:
10
+ #
11
+ #The above copyright notice and this permission notice shall be
12
+ #included in all copies or substantial portions of the Software.
13
+ #
14
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ #LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ #WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'openssl'
23
+ require 'base64'
24
+ require 'sentry/symmetric_sentry'
25
+ require 'sentry/asymmetric_sentry'
26
+ require 'sentry/sha_sentry'
27
+ require 'sentry/symmetric_sentry_callback'
28
+ require 'sentry/asymmetric_sentry_callback'
29
+
30
+ module Sentry
31
+ class NoKeyError < StandardError
32
+ end
33
+ class NoPublicKeyError < StandardError
34
+ end
35
+ class NoPrivateKeyError < StandardError
36
+ end
37
+ end
38
+
39
+ begin
40
+ require 'active_record/sentry'
41
+ ActiveRecord::Base.class_eval do
42
+ include ActiveRecord::Sentry
43
+ end
44
+ rescue NameError
45
+ nil
46
+ end
@@ -0,0 +1,144 @@
1
+ module Sentry
2
+ class AsymmetricSentry
3
+ attr_reader :private_key_file
4
+ attr_reader :public_key_file
5
+ attr_accessor :symmetric_algorithm
6
+ @@default_private_key_file = nil
7
+ @@default_public_key_file = nil
8
+ @@default_symmetric_algorithm = nil
9
+
10
+ # available options:
11
+ # * <tt>:private_key_file</tt> - encrypted private key file
12
+ # * <tt>:public_key_file</tt> - public key file
13
+ # * <tt>:symmetric_algorithm</tt> - algorithm to use for SymmetricSentry
14
+ def initialize(options = {})
15
+ @public_key = @private_key = nil
16
+ private_key_file = options[:private_key_file]
17
+ public_key_file = options[:public_key_file] || @@default_public_key_file
18
+ @symmetric_algorithm = options[:symmetric_algorithm] || @@default_symmetric_algorithm
19
+ end
20
+
21
+ def encrypt(data)
22
+ raise NoPublicKeyError unless public?
23
+ public_rsa.public_encrypt(data)
24
+ end
25
+
26
+ def encrypt_to_base64(data)
27
+ Base64.encode64(encrypt(data))
28
+ end
29
+
30
+ def decrypt(data, key = nil)
31
+ raise NoPrivateKeyError unless private?
32
+ private_rsa(key).private_decrypt(data)
33
+ end
34
+
35
+ def decrypt_from_base64(data, key = nil)
36
+ decrypt(Base64.decode64(data), key)
37
+ end
38
+
39
+ def private_key_file=(file)
40
+ @private_key_file = file and load_private_key
41
+ end
42
+
43
+ def public_key_file=(file)
44
+ @public_key_file = file and load_public_key
45
+ end
46
+
47
+ def public?
48
+ return true unless @public_key.nil?
49
+ load_public_key and return @public_key
50
+ end
51
+
52
+ def private?
53
+ return true unless @private_key.nil?
54
+ load_private_key and return @private_key
55
+ end
56
+
57
+ class << self
58
+ # * <tt>:key</tt> - secret password
59
+ # * <tt>:symmetric_algorithm</tt> - symmetrical algorithm to use
60
+ def save_random_rsa_key(private_key_file, public_key_file, options = {})
61
+ rsa = OpenSSL::PKey::RSA.new(512)
62
+ public_key = rsa.public_key
63
+ private_key = options[:key] ?
64
+ SymmetricSentry.new(:algorithm => options[:symmetric_algorithm]).encrypt_to_base64(rsa.to_s, options[:key]) :
65
+ rsa.to_s
66
+ File.open(public_key_file, 'w') { |f| f.write(public_key) }
67
+ File.open(private_key_file, 'w') { |f| f.write(private_key) }
68
+ end
69
+
70
+ def encrypt(data)
71
+ self.new.encrypt(data)
72
+ end
73
+
74
+ def encrypt_to_base64(data)
75
+ self.new.encrypt_to_base64(data)
76
+ end
77
+
78
+ def decrypt(data, key = nil)
79
+ self.new.decrypt(data, key)
80
+ end
81
+
82
+ def decrypt_from_base64(data, key = nil)
83
+ self.new.decrypt_from_base64(data, key)
84
+ end
85
+
86
+ # cattr_accessor would be lovely
87
+ def default_private_key_file
88
+ @@default_private_key_file
89
+ end
90
+
91
+ def default_private_key_file=(value)
92
+ @@default_private_key_file = value
93
+ end
94
+
95
+ def default_public_key_file
96
+ @@default_public_key_file
97
+ end
98
+
99
+ def default_public_key_file=(value)
100
+ @@default_public_key_file = value
101
+ end
102
+
103
+ def default_symmetric_algorithm
104
+ @@default_symmetric_algorithm
105
+ end
106
+
107
+ def default_symmetric_algorithm=(value)
108
+ @@default_symmetric_algorithm = value
109
+ end
110
+ end
111
+
112
+ private
113
+ def encryptor
114
+ @encryptor ||= SymmetricSentry.new(:algorithm => @symmetric_algorithm)
115
+ end
116
+
117
+ def load_private_key
118
+ @private_rsa = nil
119
+ @private_key_file ||= @@default_private_key_file
120
+ if @private_key_file and File.file?(@private_key_file)
121
+ @private_key = File.open(@private_key_file) { |f| f.read }
122
+ end
123
+ end
124
+
125
+ def load_public_key
126
+ @public_rsa = nil
127
+ @public_key_file ||= @@default_public_key_file
128
+ if @public_key_file and File.file?(@public_key_file)
129
+ @public_key = File.open(@public_key_file) { |f| f.read }
130
+ end
131
+ end
132
+
133
+ # retrieves private rsa from encrypted private key
134
+ def private_rsa(key = nil)
135
+ return @private_rsa ||= OpenSSL::PKey::RSA.new(@private_key) unless key
136
+ OpenSSL::PKey::RSA.new(encryptor.decrypt_from_base64(@private_key, key))
137
+ end
138
+
139
+ # retrieves public rsa
140
+ def public_rsa
141
+ @public_rsa ||= OpenSSL::PKey::RSA.new(@public_key)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,17 @@
1
+ module Sentry
2
+ class AsymmetricSentryCallback
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}=", AsymmetricSentry.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
@@ -0,0 +1,41 @@
1
+ require 'digest/sha1'
2
+ module Sentry
3
+ class ShaSentry
4
+ @@salt = 'salt'
5
+ attr_accessor :salt
6
+
7
+ # Encrypts data using SHA.
8
+ def encrypt(data)
9
+ self.class.encrypt(data + salt.to_s)
10
+ end
11
+
12
+ # Initialize the class.
13
+ # Used by ActiveRecord::Base#generates_crypted to set up as a callback object for a model
14
+ def initialize(attribute = nil)
15
+ @attribute = attribute
16
+ end
17
+
18
+ # Performs encryption on before_validation Active Record callback
19
+ def before_validation(model)
20
+ return unless model.send(@attribute)
21
+ model.send("crypted_#{@attribute}=", encrypt(model.send(@attribute)))
22
+ end
23
+
24
+ class << self
25
+ # Gets the class salt value used when encrypting
26
+ def salt
27
+ @@salt
28
+ end
29
+
30
+ # Sets the class salt value used when encrypting
31
+ def salt=(value)
32
+ @@salt = value
33
+ end
34
+
35
+ # Encrypts the data
36
+ def encrypt(data)
37
+ Digest::SHA1.hexdigest(data + @@salt)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,79 @@
1
+ module Sentry
2
+ class SymmetricSentry
3
+ @@default_algorithm = 'DES-EDE3-CBC'
4
+ @@default_key = nil
5
+ attr_accessor :algorithm
6
+ def initialize(options = {})
7
+ @algorithm = options[:algorithm] || @@default_algorithm
8
+ end
9
+
10
+ def encrypt(data, key = nil)
11
+ key = check_for_key!(key)
12
+ des = encryptor
13
+ des.encrypt(key)
14
+ data = des.update(data)
15
+ data << des.final
16
+ end
17
+
18
+ def encrypt_to_base64(text, key = nil)
19
+ Base64.encode64(encrypt(text, key))
20
+ end
21
+
22
+ def decrypt(data, key = nil)
23
+ key = check_for_key!(key)
24
+ des = encryptor
25
+ des.decrypt(key)
26
+ text = des.update(data)
27
+ text << des.final
28
+ end
29
+
30
+ def decrypt_from_base64(text, key = nil)
31
+ decrypt(Base64.decode64(text), key)
32
+ end
33
+
34
+ class << self
35
+ def default_algorithm
36
+ @@default_algorithm
37
+ end
38
+
39
+ def default_algorithm=(value)
40
+ @@default_algorithm = value
41
+ end
42
+
43
+ def default_key
44
+ @@default_key
45
+ end
46
+
47
+ def default_key=(value)
48
+ @@default_key = value
49
+ end
50
+
51
+ def encrypt(data, key = nil)
52
+ self.new.encrypt(data, key)
53
+ end
54
+
55
+ def encrypt_to_base64(text, key = nil)
56
+ self.new.encrypt_to_base64(text, key)
57
+ end
58
+
59
+ def decrypt(data, key = nil)
60
+ self.new.decrypt(data, key)
61
+ end
62
+
63
+ def decrypt_from_base64(text, key = nil)
64
+ self.new.decrypt_from_base64(text, key)
65
+ end
66
+ end
67
+
68
+ private
69
+ def encryptor
70
+ @encryptor ||= OpenSSL::Cipher::Cipher.new(@algorithm)
71
+ end
72
+
73
+ def check_for_key!(key)
74
+ valid_key = key || @@default_key
75
+ raise Sentry::NoKeyError if valid_key.nil?
76
+ valid_key
77
+ end
78
+ end
79
+ end
@@ -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
@@ -0,0 +1,25 @@
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/binding_of_caller'
8
+ require 'active_support/breakpoint'
9
+ require 'connection'
10
+ require 'sentry'
11
+
12
+ class Test::Unit::TestCase #:nodoc:
13
+ def create_fixtures(*table_names)
14
+ if block_given?
15
+ Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names) { yield }
16
+ else
17
+ Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names)
18
+ end
19
+ end
20
+ end
21
+
22
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
23
+ Test::Unit::TestCase.use_instantiated_fixtures = false
24
+ Test::Unit::TestCase.use_transactional_fixtures = (ENV['AR_TX_FIXTURES'] == "yes")
25
+
@@ -0,0 +1,61 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/user'
3
+
4
+ class AsymmetricSentryCallbackTest < Test::Unit::TestCase
5
+ fixtures :users
6
+
7
+ def setup
8
+ @str = 'sentry'
9
+ @key = 'secret'
10
+ @public_key_file = File.dirname(__FILE__) + '/keys/public'
11
+ @private_key_file = File.dirname(__FILE__) + '/keys/private'
12
+ @encrypted_public_key_file = File.dirname(__FILE__) + '/keys/encrypted_public'
13
+ @encrypted_private_key_file = File.dirname(__FILE__) + '/keys/encrypted_private'
14
+
15
+ @orig = 'sentry'
16
+ Sentry::AsymmetricSentry.default_public_key_file = @public_key_file
17
+ Sentry::AsymmetricSentry.default_private_key_file = @private_key_file
18
+ end
19
+
20
+ def test_should_encrypt_creditcard
21
+ u = User.create :login => 'jones'
22
+ u.creditcard = @orig
23
+ assert u.save
24
+ assert !u.crypted_creditcard.empty?
25
+ end
26
+
27
+ def test_should_decrypt_creditcard
28
+ assert_equal @orig, users(:user_1).creditcard
29
+ end
30
+
31
+ def test_should_not_decrypt_encrypted_creditcard_with_invalid_key
32
+ assert_nil users(:user_2).creditcard
33
+ assert_nil users(:user_2).creditcard(@key)
34
+ use_encrypted_keys
35
+ assert_nil users(:user_1).creditcard
36
+ end
37
+
38
+ def test_should_not_decrypt_encrypted_creditcard
39
+ use_encrypted_keys
40
+ assert_nil users(:user_2).creditcard
41
+ assert_nil users(:user_2).creditcard('other secret')
42
+ end
43
+
44
+ def test_should_encrypt_encrypted_creditcard
45
+ use_encrypted_keys
46
+ u = User.create :login => 'jones'
47
+ u.creditcard = @orig
48
+ assert u.save
49
+ assert !u.crypted_creditcard.empty?
50
+ end
51
+
52
+ def test_should_decrypt_encrypted_creditcard
53
+ use_encrypted_keys
54
+ assert_equal @orig, users(:user_2).creditcard(@key)
55
+ end
56
+
57
+ def use_encrypted_keys
58
+ Sentry::AsymmetricSentry.default_public_key_file = @encrypted_public_key_file
59
+ Sentry::AsymmetricSentry.default_private_key_file = @encrypted_private_key_file
60
+ end
61
+ end
@@ -0,0 +1,88 @@
1
+ require 'abstract_unit'
2
+
3
+ class AsymmetricSentryTest < Test::Unit::TestCase
4
+ def setup
5
+ @str = 'sentry'
6
+ @key = 'secret'
7
+ @public_key_file = File.dirname(__FILE__) + '/keys/public'
8
+ @private_key_file = File.dirname(__FILE__) + '/keys/private'
9
+ @encrypted_public_key_file = File.dirname(__FILE__) + '/keys/encrypted_public'
10
+ @encrypted_private_key_file = File.dirname(__FILE__) + '/keys/encrypted_private'
11
+ @sentry = Sentry::AsymmetricSentry.new
12
+
13
+ @orig = 'sentry'
14
+ @data = "vYfMxtVB8ezXmQKSNqTC9sPgi8TbsYRxWd7DVbpprzyuEdZ7gftJ/0IXsbXm\nXCU08bTAl0uEFm7dau+eJMXEJg==\n"
15
+ @encrypted_data = "q2obYAITmK93ylzVS01mJx1jSlnmylMX15nFpb4uKesVgnqvtzBRHZ/SK+Nm\nEzceIoAcJc3DHosVa4VUE/aK/A==\n"
16
+ Sentry::AsymmetricSentry.default_public_key_file = nil
17
+ Sentry::AsymmetricSentry.default_private_key_file = nil
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_files_with_default_key_using_class_method
53
+ set_default_key_files @public_key_file, @private_key_file
54
+ assert_equal @orig, Sentry::AsymmetricSentry.decrypt_from_base64(@data)
55
+ end
56
+
57
+ def test_should_decrypt_files_with_default_encrypted_key_using_class_method
58
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
59
+ assert_equal @orig, Sentry::AsymmetricSentry.decrypt_from_base64(@encrypted_data, @key)
60
+ end
61
+
62
+ def test_should_read_key_files_with_default_key
63
+ assert !@sentry.public?
64
+ assert !@sentry.private?
65
+ set_default_key_files @public_key_file, @private_key_file
66
+ end
67
+
68
+ def test_should_read_encrypted_key_files_with_default_key
69
+ assert !@sentry.public?
70
+ assert !@sentry.private?
71
+ set_default_key_files @encrypted_public_key_file, @encrypted_private_key_file
72
+ end
73
+
74
+ private
75
+ def set_key_files(public_key, private_key)
76
+ @sentry.public_key_file = public_key
77
+ @sentry.private_key_file = private_key
78
+ assert @sentry.private?
79
+ assert @sentry.public?
80
+ end
81
+
82
+ def set_default_key_files(public_key, private_key)
83
+ Sentry::AsymmetricSentry.default_public_key_file = public_key
84
+ Sentry::AsymmetricSentry.default_private_key_file = private_key
85
+ assert @sentry.private?
86
+ assert @sentry.public?
87
+ end
88
+ end
@@ -0,0 +1,14 @@
1
+ print "Using native DB2\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'arsentry'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "db2",
10
+ :host => "localhost",
11
+ :username => "arunit",
12
+ :password => "arunit",
13
+ :database => db1
14
+ )
@@ -0,0 +1,14 @@
1
+ print "Using native MySQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_sentry'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "mysql",
10
+ :host => "localhost",
11
+ :username => "rails",
12
+ :password => "",
13
+ :database => db1
14
+ )
@@ -0,0 +1,15 @@
1
+ print "Using OCI Oracle\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new STDOUT
5
+ ActiveRecord::Base.logger.level = Logger::WARN
6
+
7
+ db1 = 'activerecord_sentry'
8
+
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'oci',
11
+ :host => '', # can use an oracle SID
12
+ :username => 'arunit',
13
+ :password => 'arunit',
14
+ :database => db1
15
+ )
@@ -0,0 +1,14 @@
1
+ print "Using native PostgreSQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_sentry'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "postgresql",
10
+ :host => nil,
11
+ :username => "postgres",
12
+ :password => "postgres",
13
+ :database => db1
14
+ )
@@ -0,0 +1,34 @@
1
+ print "Using native SQlite\n"
2
+ require 'logger'
3
+ ActiveRecord::Base.logger = Logger.new("debug.log")
4
+
5
+ class SqliteError < StandardError
6
+ end
7
+
8
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
+ sqlite_test_db = "#{BASE_DIR}/activerecord_sentry.sqlite"
10
+
11
+ def make_connection(clazz, db_file, db_definitions_file)
12
+ unless File.exist?(db_file)
13
+ puts "SQLite database not found at #{db_file}. Rebuilding it."
14
+ sqlite_command = %Q{sqlite #{db_file} "create table a (a integer); drop table a;"}
15
+ puts "Executing '#{sqlite_command}'"
16
+ raise SqliteError.new("Seems that there is no sqlite executable available") unless system(sqlite_command)
17
+ clazz.establish_connection(
18
+ :adapter => "sqlite",
19
+ :dbfile => db_file)
20
+ script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
+ # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
+ script.split(';').each do
23
+ |command|
24
+ clazz.connection.execute(command) unless command.strip.empty?
25
+ end
26
+ else
27
+ clazz.establish_connection(
28
+ :adapter => "sqlite",
29
+ :dbfile => db_file)
30
+ end
31
+ end
32
+
33
+ make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
34
+
@@ -0,0 +1,33 @@
1
+ print "Using native SQLite3\n"
2
+ require 'logger'
3
+ ActiveRecord::Base.logger = Logger.new("debug.log")
4
+
5
+ class SqliteError < StandardError
6
+ end
7
+
8
+ BASE_DIR = File.expand_path(File.dirname(__FILE__) + '/../../fixtures')
9
+ sqlite_test_db = "#{BASE_DIR}/activerecord_sentry.sqlite3"
10
+
11
+ def make_connection(clazz, db_file, db_definitions_file)
12
+ unless File.exist?(db_file)
13
+ puts "SQLite3 database not found at #{db_file}. Rebuilding it."
14
+ sqlite_command = %Q{sqlite3 #{db_file} "create table a (a integer); drop table a;"}
15
+ puts "Executing '#{sqlite_command}'"
16
+ raise SqliteError.new("Seems that there is no sqlite3 executable available") unless system(sqlite_command)
17
+ clazz.establish_connection(
18
+ :adapter => "sqlite3",
19
+ :dbfile => db_file)
20
+ script = File.read("#{BASE_DIR}/db_definitions/#{db_definitions_file}")
21
+ # SQLite-Ruby has problems with semi-colon separated commands, so split and execute one at a time
22
+ script.split(';').each do
23
+ |command|
24
+ clazz.connection.execute(command) unless command.strip.empty?
25
+ end
26
+ else
27
+ clazz.establish_connection(
28
+ :adapter => "sqlite3",
29
+ :dbfile => db_file)
30
+ end
31
+ end
32
+
33
+ make_connection(ActiveRecord::Base, sqlite_test_db, 'sqlite.sql')
@@ -0,0 +1,14 @@
1
+ print "Using native SQLServer\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db1 = 'activerecord_sentry'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "sqlserver",
10
+ :host => "localhost",
11
+ :username => "sa",
12
+ :password => "",
13
+ :database => db1
14
+ )
@@ -0,0 +1,15 @@
1
+ print "Using native SQLServer via ODBC\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ dsn1 = 'activerecord_sentry'
7
+
8
+ ActiveRecord::Base.establish_connection(
9
+ :adapter => "sqlserver",
10
+ :mode => "ODBC",
11
+ :host => "localhost",
12
+ :username => "sa",
13
+ :password => "",
14
+ :dsn => dsn1
15
+ )
@@ -0,0 +1 @@
1
+ drop table users;
@@ -0,0 +1,8 @@
1
+ CREATE TABLE users (
2
+ id SERIAL,
3
+ crypted_password VARCHAR(255),
4
+ crypted_creditcard VARCHAR(255),
5
+ login VARCHAR(50),
6
+ type VARCHAR(20)
7
+ );
8
+ SELECT setval('users_id_seq', 100);
@@ -0,0 +1 @@
1
+ DROP TABLE 'pages';
@@ -0,0 +1,7 @@
1
+ CREATE TABLE 'users' (
2
+ 'id' INTEGER NOT NULL PRIMARY KEY,
3
+ 'crypted_password' VARCHAR(255),
4
+ 'crypted_creditcard' VARCHAR(255),
5
+ 'login' VARCHAR(50),
6
+ 'type' VARCHAR(20)
7
+ );
@@ -0,0 +1,25 @@
1
+ class User < ActiveRecord::Base
2
+ generates_crypted :creditcard, :mode => :asymmetric
3
+
4
+ def self.validates_password
5
+ validates_presence_of :crypted_password
6
+ validates_presence_of :password, :on => :create
7
+ validates_length_of :password, :in => 4..40
8
+ end
9
+ end
10
+
11
+ class ShaUser < User
12
+ validates_password
13
+ validates_confirmation_of :password
14
+ generates_crypted :password # sha is used by default
15
+ end
16
+
17
+ class DangerousUser < User # no password confirmation
18
+ # validates_password
19
+ generates_crypted :password
20
+ end
21
+
22
+ class SymmetricUser < User
23
+ validates_password
24
+ generates_crypted :password, :mode => :symmetric
25
+ end
@@ -0,0 +1,11 @@
1
+ user_1:
2
+ id: 1
3
+ login: bob
4
+ crypted_password: "0XlmUuNpE2k=\n"
5
+ crypted_creditcard: "vYfMxtVB8ezXmQKSNqTC9sPgi8TbsYRxWd7DVbpprzyuEdZ7gftJ/0IXsbXm\nXCU08bTAl0uEFm7dau+eJMXEJg==\n"
6
+ type: SymmetricUser
7
+ user_2:
8
+ id: 2
9
+ login: fred
10
+ crypted_creditcard: "q2obYAITmK93ylzVS01mJx1jSlnmylMX15nFpb4uKesVgnqvtzBRHZ/SK+Nm\nEzceIoAcJc3DHosVa4VUE/aK/A==\n"
11
+
@@ -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
@@ -0,0 +1,4 @@
1
+ -----BEGIN RSA PUBLIC KEY-----
2
+ MEgCQQCvktJgveIcgTH98hAhMjo0g6/GVMJaYdUh+/zQn4RBWASRmwEfJqggsfKT
3
+ pSNendZQMD8kKS8J1YTBr60ToM25AgMBAAE=
4
+ -----END RSA PUBLIC KEY-----
@@ -0,0 +1,9 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIBOwIBAAJBAL/xeY6aqFx6z1ThNOwgPgxv3tsonTlCj8VkN3Ikumg6SzBuLxlV
3
+ i9gFQZ7K9Pv9o/7+xUTYODqBpVhwgLBeu2cCAwEAAQJAHyjFMfg7Yp/xLndMzxRA
4
+ 3mX+yJckRtpeWo31TktWE3syks1r9OrfmxKiStM9kFRubeBHTihZrW92TYkROLxh
5
+ uQIhAPuftVTJZFDNxeYDKIMIMqwR8KZgtuf25cv4pTxYwPqLAiEAw0gNwDJHBkvo
6
+ da4402pZNQmBA6qCSf0svDXqoEoaShUCIGBma340Oe6LJ0pb42Vv+pnZtazIWMq9
7
+ 2IQwmn1oM2bJAiEAhgP869mVRIzzi091UCG79tn+4DU0FPLasI+P5VD1mcECIQDb
8
+ 3ndvbPcElVvdJgabxyWJJsNtBBNZYPsuc6NrQyShOw==
9
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,4 @@
1
+ -----BEGIN RSA PUBLIC KEY-----
2
+ MEgCQQC/8XmOmqhces9U4TTsID4Mb97bKJ05Qo/FZDdyJLpoOkswbi8ZVYvYBUGe
3
+ yvT7/aP+/sVE2Dg6gaVYcICwXrtnAgMBAAE=
4
+ -----END RSA PUBLIC KEY-----
@@ -0,0 +1,31 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/user'
3
+
4
+ class ShaSentryTest < Test::Unit::TestCase
5
+ def setup
6
+ Sentry::ShaSentry.salt = 'salt'
7
+ end
8
+
9
+ def test_should_encrypt
10
+ assert_equal 'f438229716cab43569496f3a3630b3727524b81b', Sentry::ShaSentry.encrypt('test')
11
+ end
12
+
13
+ def test_should_encrypt_with_salt
14
+ Sentry::ShaSentry.salt = 'different salt'
15
+ assert_equal '18e3256d71529db8fa65b2eef24a69ddad7070f3', Sentry::ShaSentry.encrypt('test')
16
+ end
17
+
18
+ def test_should_encrypt_user_password
19
+ u = ShaUser.new :login => 'bob'
20
+ u.password = u.password_confirmation = 'test'
21
+ assert u.save
22
+ assert u.crypted_password = 'f438229716cab43569496f3a3630b3727524b81b'
23
+ end
24
+
25
+ def test_should_encrypt_user_password_without_confirmation
26
+ u = DangerousUser.new :login => 'bob'
27
+ u.password = 'test'
28
+ assert u.save
29
+ assert u.crypted_password = 'f438229716cab43569496f3a3630b3727524b81b'
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ require 'abstract_unit'
2
+ require 'fixtures/user'
3
+
4
+ class SymmetricSentryCallbackTest < Test::Unit::TestCase
5
+ fixtures :users
6
+
7
+ def setup
8
+ @str = 'sentry'
9
+ Sentry::SymmetricSentry.default_key = @key = 'secret'
10
+ @encrypted = "0XlmUuNpE2k=\n"
11
+ end
12
+
13
+ def test_should_encrypt_user_password
14
+ u = SymmetricUser.new :login => 'bob'
15
+ u.password = @str
16
+ assert u.save
17
+ assert_equal @encrypted, u.crypted_password
18
+ end
19
+
20
+ def test_should_decrypted_user_password
21
+ assert_equal @str, users(:user_1).password
22
+ end
23
+
24
+ def test_should_return_nil_on_invalid_key
25
+ Sentry::SymmetricSentry.default_key = 'other secret'
26
+ assert_nil users(:user_1).password
27
+ end
28
+
29
+ def test_should_raise_error_on_invalid_key
30
+ Sentry::SymmetricSentry.default_key = 'other secret'
31
+ assert_raises(OpenSSL::CipherError) { users(:user_1).password! }
32
+ end
33
+ end
@@ -0,0 +1,37 @@
1
+ require 'abstract_unit'
2
+
3
+ class SymmetricSentryTest < Test::Unit::TestCase
4
+ def setup
5
+ @str = 'sentry'
6
+ @key = 'secret'
7
+ @encrypted = "0XlmUuNpE2k=\n"
8
+ @sentry = Sentry::SymmetricSentry.new
9
+ Sentry::SymmetricSentry.default_key = nil
10
+ end
11
+
12
+ def test_should_encrypt
13
+ assert_equal @encrypted, @sentry.encrypt_to_base64(@str, @key)
14
+ end
15
+
16
+ def test_should_decrypt
17
+ assert_equal @str, @sentry.decrypt_from_base64(@encrypted, @key)
18
+ end
19
+
20
+ def test_should_encrypt_with_default_key
21
+ Sentry::SymmetricSentry.default_key = @key
22
+ assert_equal @encrypted, @sentry.encrypt_to_base64(@str)
23
+ end
24
+
25
+ def test_should_decrypt_with_default_key
26
+ Sentry::SymmetricSentry.default_key = @key
27
+ assert_equal @str, @sentry.decrypt_from_base64(@encrypted)
28
+ end
29
+
30
+ def test_should_raise_error_when_encrypt_with_no_key
31
+ assert_raises(Sentry::NoKeyError) { @sentry.encrypt_to_base64(@str) }
32
+ end
33
+
34
+ def test_should_raise_error_when_decrypt_with_no_key
35
+ assert_raises(Sentry::NoKeyError) { @sentry.decrypt_from_base64(@str) }
36
+ end
37
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift "../lib"
2
+ Dir["**/*_test.rb"].each { |f| load f }
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.10
3
+ specification_version: 1
4
+ name: sentry
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.2.8
7
+ date: 2005-09-17
8
+ summary: Sentry provides painless encryption services with a wrapper around some OpenSSL classes
9
+ require_paths:
10
+ - lib
11
+ email: technoweenie@gmail.com
12
+ homepage: http://techno-weenie.net
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: sentry
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - Rick Olson
29
+ files:
30
+ - lib/active_record
31
+ - lib/sentry
32
+ - lib/sentry.rb
33
+ - lib/active_record/sentry.rb
34
+ - lib/sentry/asymmetric_sentry.rb
35
+ - lib/sentry/asymmetric_sentry_callback.rb
36
+ - lib/sentry/sha_sentry.rb
37
+ - lib/sentry/symmetric_sentry.rb
38
+ - lib/sentry/symmetric_sentry_callback.rb
39
+ - test/abstract_unit.rb
40
+ - test/asymmetric_sentry_callback_test.rb
41
+ - test/asymmetric_sentry_test.rb
42
+ - test/connections
43
+ - test/fixtures
44
+ - test/keys
45
+ - test/sha_sentry_test.rb
46
+ - test/symmetric_sentry_callback_test.rb
47
+ - test/symmetric_sentry_test.rb
48
+ - test/tests.rb
49
+ - test/connections/native_db2
50
+ - test/connections/native_mysql
51
+ - test/connections/native_oci
52
+ - test/connections/native_postgresql
53
+ - test/connections/native_sqlite
54
+ - test/connections/native_sqlite3
55
+ - test/connections/native_sqlserver
56
+ - test/connections/native_sqlserver_odbc
57
+ - test/connections/native_db2/connection.rb
58
+ - test/connections/native_mysql/connection.rb
59
+ - test/connections/native_oci/connection.rb
60
+ - test/connections/native_postgresql/connection.rb
61
+ - test/connections/native_sqlite/connection.rb
62
+ - test/connections/native_sqlite3/connection.rb
63
+ - test/connections/native_sqlserver/connection.rb
64
+ - test/connections/native_sqlserver_odbc/connection.rb
65
+ - test/fixtures/activerecord_sentry.sqlite
66
+ - test/fixtures/activerecord_sentry.sqlite3
67
+ - test/fixtures/db_definitions
68
+ - test/fixtures/user.rb
69
+ - test/fixtures/users.yml
70
+ - test/fixtures/db_definitions/postgresql.drop.sql
71
+ - test/fixtures/db_definitions/postgresql.sql
72
+ - test/fixtures/db_definitions/sqlite.drop.sql
73
+ - test/fixtures/db_definitions/sqlite.sql
74
+ - test/keys/encrypted_private
75
+ - test/keys/encrypted_public
76
+ - test/keys/private
77
+ - test/keys/public
78
+ - README
79
+ - MIT-LICENSE
80
+ - CHANGELOG
81
+ - RUNNING_UNIT_TESTS
82
+ test_files:
83
+ - test/tests.rb
84
+ rdoc_options: []
85
+ extra_rdoc_files: []
86
+ executables: []
87
+ extensions: []
88
+ requirements: []
89
+ dependencies: []