cloak_id 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4702a69506e1c0ccc4888a32e69b04161161e20e
4
+ data.tar.gz: 4701111cd4ec15d847ca64421f54d2862bfb9fef
5
+ SHA512:
6
+ metadata.gz: daf77844a7c971e5920a567f9dc4d2b1d698e56e16289f8fcf0806d8fe86d9c0cc77e78d06c14018b8ca60f8980c87966cddfb31a62c2aea9897bf287b9f727c
7
+ data.tar.gz: 5aad2b8a0b8fef298dd5eb6bc79d8acb418e19c9b2c35a053a65006b626b351cbca31bcb9ca857e842e998906b83fab2b3c8c03985bc6abc4b03832fb31e35a0
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .idea/
24
+ coverage/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cloak_id.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 elleleb
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Beth LeBeau
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,122 @@
1
+ # CloakId
2
+
3
+ ### Hide your database ids from users of your webapp.
4
+
5
+ Using sequential ids makes predicting the ids of other resources in your application simple, and can provide details
6
+ about how your app is growing (how many users, etc.) to current and potential competitors. Obfuscating identifiers isn't
7
+ meant to be a primary means of providing security, but it can help to keep confidential information from being completely
8
+ public.
9
+
10
+ Making use of the gem will replace the identifier in URLs:
11
+ e.g. http://my.railsapp.com/users/U3OFSP23
12
+
13
+ as well as in JSON representations of resources
14
+
15
+ e.g.
16
+ {"id":"U3OFSP23", "name": "Joe User", "active":true}
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ gem 'cloak_id'
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install cloak_id
31
+
32
+ To seed the random key used during cloaking, execute the following command
33
+
34
+ rails generate cloak_id::install
35
+
36
+ This command is optional, but if it not done then your application will make use of a global default key, leading to identical
37
+ cloaked ids being generated for identically named models. This value will be used to seed the transformation, and help ensure
38
+ the quality of the obfuscation.
39
+
40
+ ## Usage
41
+
42
+ In your model files (that inherit from Active Record) add the 'cloak_id' call to enable the obfuscating of the ids.
43
+
44
+ class User < ActiveRecord::Base
45
+ cloak_id
46
+ end
47
+
48
+
49
+ ## What the gem does
50
+
51
+ The cloak_id gem provides a way to "cloak" your identifiers. This doesn't provide any real security, but instead makes it
52
+ less obvious to what the underlying database id of a resource really is. This is desirable in cases where you want to make
53
+ it more difficult for users to guess identifiers, or for observers to judge how fast your application is growing.
54
+
55
+ This technique does not provide any real security - it only makes it more difficult for casual observers to guess resource
56
+ identifiers.
57
+
58
+ The logic behind the transformation is to use a prime number to generate a simple, yet reversible hash of the database id.
59
+ That newly obscured hash is then encoded as a string, to further hide its meaning. This will happen when generating forms
60
+ from ActiveRecords (when using the entire object or the to_param call), as well as when encoding the object in JSON format.
61
+
62
+
63
+ ## Customizing your cloaking
64
+
65
+ The cloak_id method call takes an option hash that controls how the cloaking occurs:
66
+ <p>
67
+ <table>
68
+ <tr>
69
+ <th>option name</th>
70
+ <th>description</th>
71
+ </tr>
72
+ <tr>
73
+ <td>key</td>
74
+ <td>The key to use for obfuscating identifier. This can be either an integer or a string. This is an optional
75
+ parameter. If the user does not provide one, then this will be based on the name of the model itself. This
76
+ means that "common" models (e.g. User) may have the same obfuscated values across different web apps. This
77
+ can be prevented by passing in a value to this parameter or by setting a seed (by running rails generate cloak_id install)
78
+ </td>
79
+ </tr>
80
+ <tr>
81
+ <td> prefix </td>
82
+ <td> Obfuscating the identifier results in a string. To better help developers understand what type of resource
83
+ if being identified, an optional prefix may be specified. If none is provided, then a prefix will be created
84
+ based on the name of the model. This prefix must start with a alphabetic character.
85
+ </td>
86
+ </tr>
87
+ </table>
88
+
89
+ ###Examples
90
+ This line will result in a cloaked identifier encoded with a specifically defined key, and the resulting cloaked identifier
91
+ will begin with UU.
92
+
93
+ cloak_id key:'SampleKey', prefix:'UU'
94
+
95
+ After this call, most instances of the id will be replaced with the cloaked id. This includes calls to serialize the
96
+ resoruce as XML or JSON, as well as when it is used as a parameter in forms, or in RESTful API calls. The "id" call will
97
+ not change, as this gem does not actually change the underlying id of the object. Just how it is displayed.
98
+
99
+ To access the cloaked id directly, you may call
100
+ self.cloaked_id
101
+
102
+ Retrieving objects from the database from cloaked ids can happen in two ways
103
+
104
+ ClassName.find(cloaked_id)
105
+ or
106
+
107
+ ClassName.find_by_cloaked_id(cloaked_id)
108
+
109
+ Objects that have had their id cloaked will use a "smart" find method. This method will inspect the id to see if it
110
+ appears to be a cloaked id (all cloaked ids must start with an alphabetic character), and if it does, then it will use
111
+ the find_by_cloaked_id method. If it is numeric, or if it does not begin with the expected prefix, then it will fall
112
+ back to use the out-of-the-box find functionality.
113
+
114
+ Because of this logic, most cases will work without any changes to the code that makes use of the cloaked resource.
115
+
116
+ ## Contributing
117
+
118
+ 1. Fork it ( https://github.com/elleleb/cloak_id/fork )
119
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
120
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
121
+ 4. Push to the branch (`git push origin my-new-feature`)
122
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloak_id/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cloak_id"
8
+ spec.version = CloakId::VERSION
9
+ spec.authors = ["Elle L."]
10
+ spec.email = ["elle@pandromos.com"]
11
+ spec.summary = %q{Gem to help obfuscate Active Record ids.}
12
+ spec.description = %q{The cloak id gem allows developers to easily hide the actual (database) id of resources through obfuscation.}
13
+ spec.homepage = "https://github.com/elleleb/cloak_id"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "rails","> 4.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "pry"
28
+ spec.add_development_dependency "simplecov"
29
+ spec.add_development_dependency "generator_spec"
30
+ end
@@ -0,0 +1,127 @@
1
+ require "cloak_id/version"
2
+ require "active_record"
3
+ require "zlib"
4
+ require "cloak_id/cloak_id_encoder"
5
+ require "cloak_id/errors"
6
+
7
+ module CloakId
8
+
9
+ # The main entry point for cloak_id This will cause the Active Record that this is called in to be able to
10
+ # cloak it's ids.
11
+ #
12
+ # options:
13
+ # :prefix : All cloaked ids will begin with this prefix. If none is provided, then the letter 'X' will be used
14
+ # :key : The key that will be used to do the obfuscation. If none is provided, then the obfuscation will use
15
+ # a key based on the model name. This could result in multiple applications cloaking ids in the same way.
16
+ def cloak_id(options = {})
17
+ cattr_accessor :cloak_id_prefix, :cloak_id_key
18
+ self.cloak_id_prefix = (options[:prefix] || model_name.singular.split('_').slice(0,2).inject('') {|prefix,word| prefix + word[0,1].upcase})
19
+
20
+ raise CloakingError, 'Prefix values must start with a letter.' unless (/^[A-Za-z]/ =~ self.cloak_id_prefix)
21
+
22
+ key = options[:key]
23
+
24
+ if (!key.nil? and key.is_a? String)
25
+ key = Zlib::crc32(key)
26
+ end
27
+
28
+ self.cloak_id_key = key
29
+
30
+ alias_method :old_serializable_hash, :serializable_hash
31
+ extend ClassMethods
32
+ include InstanceMethods
33
+ end
34
+
35
+ module InstanceMethods
36
+
37
+ # Return the id for the object in cloaked form. If the id is nil, then this method will also return nil.
38
+ def cloaked_id
39
+ if self.id.nil?
40
+ nil
41
+ else
42
+ self.class.cloaked_id_for(self.id)
43
+ end
44
+ end
45
+
46
+ def to_param
47
+ self.cloaked_id
48
+ end
49
+
50
+ def serializable_hash (options = nil)
51
+ attribute_hash = self.old_serializable_hash (options)
52
+ attribute_hash['id'] = self.cloaked_id
53
+
54
+ #now we want to cloak any fk ids that have been cloaked
55
+ self.class.reflections.values.each do |association|
56
+ if association.klass.respond_to? :cloaked_id_for
57
+ # this is a related item that has been cloaked
58
+ if attribute_hash.has_key? association.foreign_key
59
+ attribute_hash[association.foreign_key] = association.klass.cloaked_id_for(attribute_hash[association.foreign_key])
60
+ end
61
+ end
62
+ end
63
+ attribute_hash
64
+ end
65
+ end
66
+
67
+ module ClassMethods
68
+
69
+ # class method to create the cloaked id. This will be used when generation a new cloaked id either on demand by the
70
+ # object itself, or when an association wants to hide the id.
71
+
72
+ def cloaked_id_for(id)
73
+ "#{self.cloak_id_prefix}#{CloakIdEncoder.cloak_mod_35(id, self.cloaking_key)}"
74
+ end
75
+
76
+ # Return the key that we're going to use in the twiddle function during reversible hashing
77
+ # this value will be based on the CRC check sum of the model name unless one is provided by
78
+ # the user.
79
+ def cloaking_key
80
+ self.cloak_id_key = Zlib::crc32(self.model_name)^CloakIdEncoder.cloak_id_default_key unless self.cloak_id_key.is_a? Integer
81
+ self.cloak_id_key
82
+ end
83
+
84
+ # Perform a find request based on the cloaked id. This command will verify that the cloaked id is in the
85
+ # correct format to allow it to be found. If it is not then the requested record cannot be found, and a
86
+ # RecordNotFound error will be raised.
87
+ def find_by_cloaked_id(cloaked_id,options={})
88
+ # make sure this is a valid id
89
+ raise new ActiveRecord::RecordNotFound("Cloaked Id does not have a valid format.") unless cloaked_id.start_with? self.cloak_id_prefix
90
+
91
+ decloaked_id = decloak_id_for_class(cloaked_id)
92
+ self.find(decloaked_id)
93
+ end
94
+
95
+ def decloak_id_for_class(cloaked_id)
96
+ CloakIdEncoder.decloak_mod_35(cloaked_id[self.cloak_id_prefix.length..-1], self.cloaking_key)
97
+ end
98
+
99
+ ## method to check whether an id might be a valid cloaked id.
100
+ def is_cloaked_id?(id)
101
+ id.is_a? String and id.starts_with? self.cloak_id_prefix
102
+ end
103
+
104
+ # This is a "Smart" version of the find method. It takes a look at the id, and figures out if it might be a cloaked
105
+ # id. If it is, then it will perform the search with the decloaked value. Otherwise it will treat it as a "normal"
106
+ # identifier.
107
+ def find(arg)
108
+ arg_is_cloaked_id = is_cloaked_id? arg
109
+ if arg_is_cloaked_id
110
+ find_by_cloaked_id arg
111
+ elsif arg.is_a? Array
112
+ arg_list = arg.map do |entry|
113
+ if is_cloaked_id? entry
114
+ decloak_id_for_class entry
115
+ else
116
+ entry
117
+ end
118
+ end
119
+ super arg_list
120
+ else
121
+ super arg
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ ActiveRecord::Base.extend CloakId
@@ -0,0 +1,59 @@
1
+ module CloakId
2
+ # The CloakIdEncoder is a support class that helps with the cloaking process. It provides the base functionality
3
+ # need to do the hashing back and forth from the numeric identifier, as well as the mechanism to turn this into
4
+ # a cloaked id.
5
+ class CloakIdEncoder
6
+ TWIDDLE_PRIME = 0x20C8592B
7
+
8
+ cattr_accessor :cloak_id_default_key
9
+
10
+ # Basic hashing function to go back and forth between a hashed value.
11
+ def self.twiddle(val,key)
12
+ hashed = (key ^ val) * TWIDDLE_PRIME
13
+ hashed >> (hashed & 0x0f) & 0xffff
14
+ end
15
+
16
+ # Take the integer and cloak it as another integer. This is a reversible function, and cloak(cloak(X)) = X
17
+ def self.cloak(id,key=CloakIdEncoder.cloak_id_default_key)
18
+ raise "Id must be an integer to cloak properly" unless id.is_a? Integer
19
+
20
+ low = id & 0xffff
21
+ high = ((id >> 16) & 0xffff) ^ twiddle(low,key)
22
+ ((low ^ twiddle(high,key||0)) << 16) + high
23
+ end
24
+
25
+
26
+ # This calls the cloak method, but instead of returning the integer value, it will return it as a base 36 string.
27
+ # Unlike the main cloak method, this is not reversible in the same way. To reverse the action of cloaking, the
28
+ # decloak_base36 method must be used instead.
29
+ def self.cloak_base36(id,key=CloakIdEncoder.cloak_id_default_key)
30
+ self.cloak(id,key||0).to_s(36).upcase
31
+ end
32
+
33
+ # This method reverses the cloaking procedure for when the ID has been cloaked using the base36 technique. It is
34
+ # important to know that this method does not handle the stripping any prefix that might have been added. It acts
35
+ # only as an inverse function to the cloak_base36 function
36
+ def self.decloak_base36(cloaked_id, key=CloakIdEncoder.cloak_id_default_key)
37
+ id = cloaked_id.downcase.to_i(36)
38
+ cloak(id,key||0)
39
+ end
40
+
41
+ # The modified base 35 encoding eliminates Z's from appearing normallty. This was we can make cloaked id's at least
42
+ # a given length. This can help make the representation of the cloaked id, a little bit more homogenized.
43
+ def self.cloak_mod_35(id, key=CloakIdEncoder.cloak_id_default_key, min_len=7)
44
+ intermediate_id = self.cloak(id,key||0).to_s(35).upcase
45
+ if intermediate_id.length < min_len
46
+ "#{"Z"*(min_len-intermediate_id.length)}#{intermediate_id}"
47
+ else
48
+ intermediate_id
49
+ end
50
+ end
51
+
52
+ # Preform the decloaking operation for the modified base 35 encoding scheme. This will remove the "Z" characters that
53
+ # only serve to be place holders, then turn it back into a number and decloak it.
54
+ def self.decloak_mod_35(id,key=CloakIdEncoder.cloak_id_default_key)
55
+ intermediate_id = id.slice(/[0-9A-Y]+/).downcase.to_i(35)
56
+ self.cloak(intermediate_id,key)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,6 @@
1
+ module CloakId
2
+ # A standard error to represent problems with the cloaking process. This error should be raised when there is a
3
+ # problem that must be handled to ensure proper functionality.
4
+ class CloakingError < StandardError
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module CloakId
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ module CloakId
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def generate_install
7
+ template 'cloak_id.rb.erb', 'config/initializers/cloak_id.rb'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ # This will set the global key for the application. This is generated at install time to help
2
+ # to better cloak the ids in the app.
3
+ CloakId::CloakIdEncoder.cloak_id_default_key = <%=SecureRandom.random_number(0xffffffff)%>
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require File.dirname(__FILE__)+'/../../lib/cloak_id/cloak_id_encoder'
3
+
4
+ describe CloakId::CloakIdEncoder do
5
+
6
+ it 'should raise exception when the id to be cloaked is not numeric' do
7
+ expect {CloakId::CloakIdEncoder.cloak(id)}.to raise_error
8
+ end
9
+
10
+ it 'should return the base id after cloaking twice' do
11
+ cloaked_v = CloakId::CloakIdEncoder.cloak(10000,0)
12
+ expect(CloakId::CloakIdEncoder.cloak(cloaked_v,0)).to eql 10000
13
+
14
+ cloaked_v = CloakId::CloakIdEncoder.cloak(0xffff25,0x1234)
15
+ expect(CloakId::CloakIdEncoder.cloak(cloaked_v,0x1234)).to eql 0xffff25
16
+ end
17
+
18
+ it 'should be able to perform a base 36 encoding and decoding successfully' do
19
+ cloaked_v = CloakId::CloakIdEncoder.cloak_base36(10000,0)
20
+ decloaked_v = CloakId::CloakIdEncoder.decloak_base36(cloaked_v,0)
21
+ expect(decloaked_v).to eql 10000
22
+ end
23
+
24
+ it 'should enforce a minimum length when using modified base 35 encoding' do
25
+ cloaked_v = CloakId::CloakIdEncoder.cloak_mod_35(10000,0,40)
26
+
27
+ expect(cloaked_v).to include 'ZZZZZZZZZ'
28
+ expect(cloaked_v).to have(40).characters
29
+
30
+ decloaked_id = CloakId::CloakIdEncoder.decloak_mod_35(cloaked_v,0)
31
+ expect(decloaked_id).to eql 10000
32
+ end
33
+
34
+
35
+ it 'should not modify the cloaked id if the cloaked value is already long enough' do
36
+ cloaked_v = CloakId::CloakIdEncoder.cloak_mod_35(10000,0,5)
37
+ expect(cloaked_v).to_not include 'Z'
38
+ expect(cloaked_v).to have_at_least(5).characters
39
+ end
40
+
41
+ it 'should make use of the configured default key when none is provided' do
42
+ key_0_cloaked = CloakId::CloakIdEncoder.cloak_mod_35(1234)
43
+ CloakId::CloakIdEncoder.cloak_id_default_key = 4321
44
+ key_4321_cloaked = CloakId::CloakIdEncoder.cloak_mod_35(1234)
45
+ key_4321_decloaked = CloakId::CloakIdEncoder.decloak_mod_35(key_4321_cloaked)
46
+
47
+ expect(key_4321_decloaked).to eql 1234
48
+ expect(key_0_cloaked).to_not eql key_4321_cloaked
49
+ end
50
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ ## helper to make a simple model
5
+ def make_model
6
+ test_model = TestModel.new
7
+ test_model.id = 1234
8
+ test_model.test_field='This is a test field'
9
+
10
+ test_model
11
+ end
12
+
13
+ describe CloakId do
14
+
15
+ it 'should provide the obfuscated id on an active record' do
16
+ test_model = make_model()
17
+ cloaked_id = test_model.cloaked_id
18
+
19
+ expect(cloaked_id).to start_with 'TM'
20
+ decloaked_id = CloakId::CloakIdEncoder.decloak_mod_35(cloaked_id[2..-1],test_model.cloak_id_key)
21
+ expect(decloaked_id).to eql test_model.id
22
+ end
23
+
24
+ it 'should use the specified prefix on the front of the cloaked id' do
25
+ test_model = TestModel.create
26
+ test_association = TestAssociation.create
27
+
28
+ expect(test_model.cloaked_id).to start_with 'TM' #default
29
+ expect(test_association.cloaked_id).to start_with 'L'
30
+ end
31
+
32
+ it 'should be able to convert a string key into a numeric key for cloaking' do
33
+ expect(TestModel2.cloaking_key).to eql Zlib::crc32('my_key')
34
+ end
35
+
36
+ it 'should raise an error when using a prefix that does not start with a letter' do
37
+ sample_model = UncloakedModel.new
38
+ expect do
39
+ class << sample_model
40
+ cloak_id prefix:'123'
41
+ end
42
+ end.to raise_error(CloakId::CloakingError)
43
+ end
44
+
45
+ it 'should return null for the cloaked id when there is no id in place' do
46
+ model = TestModel.new
47
+
48
+ expect(model.cloaked_id).to be_nil
49
+ end
50
+
51
+ it 'should allow the user to used the find_by_cloaked_id method to use the cloaked id to find the resource' do
52
+ model = TestModel.create
53
+ cloaked_id = model.cloaked_id
54
+
55
+ found_model = TestModel.find_by_cloaked_id(cloaked_id)
56
+ expect(found_model).to eql model
57
+ end
58
+
59
+ it 'should provide the cloaked id when converting the resource into a parameter' do
60
+ model = make_model()
61
+ expect(model.to_param).to eql model.cloaked_id
62
+ end
63
+
64
+ it 'should include the cloaked id in the json that is produced for the resource' do
65
+ test_model = make_model()
66
+ model_json = test_model.as_json
67
+ expect(model_json['id']).to eql test_model.cloaked_id
68
+ end
69
+
70
+
71
+ it 'should handle cloaking ids with the JSON as it bubbles up' do
72
+ model = TestModel.create
73
+ association = TestAssociation.create
74
+
75
+ model.test_associations << association
76
+ model.test_associations << TestAssociation.create
77
+ model_json = model.as_json(include: :test_associations)
78
+
79
+ # This is ugly, but since this is a single association on the model, we want the first item in the "has many"
80
+ expect(model_json['test_associations'][0]['id']).to eql association.cloaked_id
81
+ expect(model_json['test_associations'][0]['test_model_id']).to eql model.cloaked_id
82
+ end
83
+
84
+ it 'should use the right find technique when presented with the cloaked vs. the decloaked id.' do
85
+ model = TestModel.create
86
+ model_2 = TestModel.create
87
+ expect(TestModel.find(model.id)).to eql model
88
+ expect(TestModel.find(model.cloaked_id)).to eql model
89
+ expect(TestModel.find([model.id, model_2.id])).to eql [model,model_2]
90
+ expect(TestModel.find([model.cloaked_id, model_2.cloaked_id])).to eql [model,model_2]
91
+ end
92
+ end
@@ -0,0 +1,20 @@
1
+ # Spec file for the installation generator.
2
+ require 'spec_helper'
3
+ require 'generator_spec/test_case'
4
+ require 'generators/cloak_id/install/install_generator'
5
+
6
+ describe CloakId::Generators::InstallGenerator do
7
+ include GeneratorSpec::TestCase
8
+ destination File.expand_path('../../tmp',__FILE__)
9
+
10
+ before (:all) do
11
+ SecureRandom.stub(:random_number).and_return(12345)
12
+ prepare_destination
13
+ run_generator
14
+ end
15
+
16
+ it 'should create an initializer' do
17
+ # We're going to check to make sure that the file has the expected key in it.
18
+ assert_file 'config/initializers/cloak_id.rb',/CloakId::CloakIdEncoder.cloak_id_default_key = 12345/
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ ActiveRecord::Schema.define do
2
+ self.verbose = false
3
+
4
+ create_table :test_models, :force => true do |t|
5
+ t.string :test_field
6
+ end
7
+
8
+ create_table :test_associations, :force => true do |t|
9
+ t.references :test_model
10
+ end
11
+
12
+ create_table :uncloaked_models, :force => true do |t|
13
+ t.string :extra_field_for_sample
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require 'active_record'
6
+ require 'pry'
7
+
8
+ Bundler.setup
9
+ require 'cloak_id' # and any other gems you need
10
+ require 'support/test_model'
11
+ require 'zlib'
12
+
13
+ RSpec.configure do |config|
14
+ config.debug = false
15
+ config.color_enabled = true
16
+ config.formatter = 'documentation'
17
+ end
18
+
19
+ ActiveRecord::Base.establish_connection adapter:'sqlite3', database:':memory:'
20
+
21
+ load File.dirname(__FILE__) + '/schema.rb'
@@ -0,0 +1,20 @@
1
+ # Here lie model classes that help with the unit tests. We'll use these to create certain sub-categories of
2
+ # models that have cloaked ids.
3
+ class TestModel < ActiveRecord::Base
4
+ cloak_id
5
+ has_many :test_associations
6
+ end
7
+
8
+ class TestAssociation < ActiveRecord::Base
9
+ cloak_id prefix:'L'
10
+ belongs_to :test_model
11
+ end
12
+
13
+ class UncloakedModel < ActiveRecord::Base
14
+ end
15
+
16
+ class TestModel2 < ActiveRecord::Base
17
+ self.table_name = 'test_models'
18
+
19
+ cloak_id key:'my_key'
20
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloak_id
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Elle L.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sqlite3
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: generator_spec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: The cloak id gem allows developers to easily hide the actual (database)
126
+ id of resources through obfuscation.
127
+ email:
128
+ - elle@pandromos.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - Gemfile
135
+ - LICENSE
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - cloak_id.gemspec
140
+ - lib/cloak_id.rb
141
+ - lib/cloak_id/cloak_id_encoder.rb
142
+ - lib/cloak_id/errors.rb
143
+ - lib/cloak_id/version.rb
144
+ - lib/generators/cloak_id/install/install_generator.rb
145
+ - lib/generators/cloak_id/install/templates/cloak_id.rb.erb
146
+ - spec/cloak_id/cloak_id_encoder_spec.rb
147
+ - spec/cloak_id/cloak_id_spec.rb
148
+ - spec/cloak_id/install_generator_spec.rb
149
+ - spec/schema.rb
150
+ - spec/spec_helper.rb
151
+ - spec/support/test_model.rb
152
+ homepage: https://github.com/elleleb/cloak_id
153
+ licenses:
154
+ - MIT
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.2.2
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Gem to help obfuscate Active Record ids.
176
+ test_files:
177
+ - spec/cloak_id/cloak_id_encoder_spec.rb
178
+ - spec/cloak_id/cloak_id_spec.rb
179
+ - spec/cloak_id/install_generator_spec.rb
180
+ - spec/schema.rb
181
+ - spec/spec_helper.rb
182
+ - spec/support/test_model.rb