cloak_id 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,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