sentry 0.2.8

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 (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: []