obfuscate_id 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +77 -0
- data/Rakefile +27 -0
- data/lib/obfuscate_id.rb +53 -0
- data/lib/obfuscate_id/run_scatter_swap.rb +93 -0
- data/lib/obfuscate_id/scatter_swap.rb +138 -0
- data/lib/obfuscate_id/version.rb +3 -0
- data/lib/tasks/obfuscate_id_tasks.rake +4 -0
- metadata +127 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Nathan Amick
|
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.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
# ObfuscateId
|
2
|
+
|
3
|
+
ObfuscateId is a simple Ruby on Rails plugin that hides your seqential Active Record ids. Although having nothing to do with security, it can be used to make database record id information non-obvious.
|
4
|
+
|
5
|
+
For new websites, you may not want to give away information about how many people are signed up. Every website has a third user, but that third user doesn't have to know he is the third user.
|
6
|
+
|
7
|
+
ObfuscateId turns a URL like this:
|
8
|
+
|
9
|
+
http://example.com/users/3
|
10
|
+
|
11
|
+
into something like:
|
12
|
+
|
13
|
+
http://example.com/users/2356513904
|
14
|
+
|
15
|
+
ObfuscateId mixes up the ids in a simple, reversable hashing algorithm so that it can then automatically revert the hashed number back to 3 for record lookup without having to store a hash or tag in the database. No migrations needed.
|
16
|
+
|
17
|
+
If you have the opposite problem, and your site is scaling well, you might not want to leak that you are getting 50 new posts a minute.
|
18
|
+
|
19
|
+
ObfuscateId turns your sequential Active Record ids into non-sequential, random looking, numeric ids.
|
20
|
+
|
21
|
+
# post 7000
|
22
|
+
http://example.com/posts/5270192353
|
23
|
+
# post 7001
|
24
|
+
http://example.com/posts/7107163820
|
25
|
+
# post 7002
|
26
|
+
http://example.com/posts/3296163828
|
27
|
+
|
28
|
+
## Features
|
29
|
+
|
30
|
+
* Extreemly simple. A single line of code in the model turns it on.
|
31
|
+
* Transforms normal seqential ids into random-looking ten digit numerical strings.
|
32
|
+
* Gently masks resource ids while retaining a cleaner look than using an encrypted hash.
|
33
|
+
* No migrations or database changes are needed. The record is still stored in the database with its original id.
|
34
|
+
* Fast, no heavy calculation.
|
35
|
+
|
36
|
+
|
37
|
+
## Installation
|
38
|
+
|
39
|
+
Add the gem to your Gemfile.
|
40
|
+
|
41
|
+
gem "obfuscate_id"
|
42
|
+
|
43
|
+
Run bundler.
|
44
|
+
|
45
|
+
bundle install
|
46
|
+
|
47
|
+
Then, in your model, add a single line.
|
48
|
+
|
49
|
+
class Post < ActiveRecord::Base
|
50
|
+
obfuscate_id
|
51
|
+
end
|
52
|
+
|
53
|
+
## Customization
|
54
|
+
|
55
|
+
If you want your obfuscated ids to be different than some other website using the same plugin, you can throw a random number (spin) at obfuscate_id to make it hash out unique ids for your app.
|
56
|
+
|
57
|
+
class Post < ActiveRecord::Base
|
58
|
+
obfuscate_id :spin => 89238723
|
59
|
+
end
|
60
|
+
|
61
|
+
This is also useful for making different models in the same app have different obfuscated ids.
|
62
|
+
|
63
|
+
## How it works
|
64
|
+
|
65
|
+
ObfuscateId pairs each number, from 0 to 9999999999, with one and only one number in that same range. That other number is paired back to the first. This is an example of a minimal perfect hash function. Within a set of ten billion numbers, it simply maps every number to a different 10 digit number, and back again.
|
66
|
+
|
67
|
+
ObfuscateId switches the plain record id to the obfuscated id in the models `to_param` method.
|
68
|
+
|
69
|
+
It then augments Active Record's `find` method on models that have have been initiated with the `obfuscate_id` method to quickly reverse this obfuscated id back to the plain id before building the database query. This means no migrations or changes to the database.
|
70
|
+
|
71
|
+
## Limitations
|
72
|
+
|
73
|
+
* This is not security. ObfuscateId was created to lightly mask record id numbers for the casual user. If you need to really secure your database ids (hint, you probably don't), you need to use real encryption like AES.
|
74
|
+
* Works for up to ten billion database records. ObfuscateId simply maps every integer below ten billion to some other number below ten billion.
|
75
|
+
* To properly generate obfuscated urls, make sure you trigger the model's `to_param` method by passing in the whole object rather than just the id; do this: `post_path(@post)` not this: `post_path(@post.id)`.
|
76
|
+
* Rails uses the real id rather than `to_param` in some places. A simple view-source on a form will often show the real id. This can be avoided by taking certain precautions.
|
77
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ObfuscateId'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
data/lib/obfuscate_id.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module ObfuscateId
|
2
|
+
|
3
|
+
def obfuscate_id(options = {})
|
4
|
+
require 'obfuscate_id/scatter_swap'
|
5
|
+
extend ClassMethods
|
6
|
+
include InstanceMethods
|
7
|
+
cattr_accessor :obfuscate_id_spin
|
8
|
+
self.obfuscate_id_spin = (options[:spin] || obfuscate_id_default_spin)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.hide(id)
|
12
|
+
ScatterSwap.hash(id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.show(id)
|
16
|
+
ScatterSwap.reverse_hash(id)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def find(*args)
|
22
|
+
if has_obfuscated_id?
|
23
|
+
args[0] = ObfuscateId.show(args[0])
|
24
|
+
end
|
25
|
+
super(*args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_obfuscated_id?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
# Generate a default spin from the Model name
|
33
|
+
# This makes it easy to drop obfuscate_id onto any model
|
34
|
+
# and produce different obfuscated ids for different models
|
35
|
+
def obfuscate_id_default_spin
|
36
|
+
alphabet = Array("a".."z")
|
37
|
+
number = name.split("").collect do |char|
|
38
|
+
alphabet.index(char)
|
39
|
+
end
|
40
|
+
number.join.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module InstanceMethods
|
46
|
+
def to_param
|
47
|
+
ObfuscateId.hide(self.id)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
ActiveRecord::Base.extend ObfuscateId
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require './scatter_swap.rb'
|
2
|
+
|
3
|
+
# This file isn't really part of the library, its pretty much spike code..
|
4
|
+
#
|
5
|
+
# While developing this, I used this file to visualize what was going on with the numbers
|
6
|
+
#
|
7
|
+
# You can uncomment various methods at the bottom and then run it like this:
|
8
|
+
#
|
9
|
+
# watch -n1 ruby run_scatter_swap.rb
|
10
|
+
#
|
11
|
+
# tweak the code a bit and see instant visual changes in the generated numbers
|
12
|
+
|
13
|
+
def visualize_scatter_and_unscatter
|
14
|
+
# change this number to experiment with different values
|
15
|
+
rotations = 99
|
16
|
+
|
17
|
+
original = ScatterSwap.arrayify(123456789)
|
18
|
+
scattered = []
|
19
|
+
unscattered = []
|
20
|
+
puts original.join
|
21
|
+
puts "rotate!(#{rotations})"
|
22
|
+
10.times do
|
23
|
+
puts original.rotate!(rotations).join + "->" + scattered.push(original.pop).join
|
24
|
+
end
|
25
|
+
puts "scattered"
|
26
|
+
puts scattered.join
|
27
|
+
10.times do
|
28
|
+
puts unscattered.push(scattered.pop).join + "->" + unscattered.rotate!(rotations * -1).join
|
29
|
+
end
|
30
|
+
|
31
|
+
puts unscattered.join
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def visualize_swapper_map
|
36
|
+
puts "swapper map"
|
37
|
+
10.times do |index|
|
38
|
+
key = 1
|
39
|
+
puts ScatterSwap.swapper_map(index).join.to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def visualize_hash
|
44
|
+
puts "hash"
|
45
|
+
40.times do |integer|
|
46
|
+
output = "|"
|
47
|
+
3.times do |index|
|
48
|
+
output += " #{(integer + (123456789 * index)).to_s.rjust(5, ' ')}"
|
49
|
+
output += " => #{hashed = ScatterSwap.hash(integer + (123456789 * index) ) }"
|
50
|
+
output += " => #{ScatterSwap.reverse_hash(hashed) } |"
|
51
|
+
end
|
52
|
+
puts output
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def visualize_scatter
|
58
|
+
puts "original scattered unscattered"
|
59
|
+
20.times do |integer|
|
60
|
+
output = ""
|
61
|
+
2.times do |index|
|
62
|
+
original = ScatterSwap.arrayify(integer + (123456789 * index))
|
63
|
+
scattered = ScatterSwap.scatter(original.clone)
|
64
|
+
unscattered = ScatterSwap.unscatter(scattered.clone)
|
65
|
+
output += "#{original.join}"
|
66
|
+
output += " => #{scattered.join}"
|
67
|
+
output += " => #{unscattered.join} | "
|
68
|
+
end
|
69
|
+
puts output
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# find hash for lots of spins
|
75
|
+
def visualize_spin
|
76
|
+
2000.times do |original|
|
77
|
+
hashed_values = []
|
78
|
+
9000000000.times do |spin|
|
79
|
+
hashed = ScatterSwap.hash(original, spin)
|
80
|
+
if hashed_values.include? hashed
|
81
|
+
puts "collision: #{original} - #{spin} - #{hashed}"
|
82
|
+
break
|
83
|
+
end
|
84
|
+
hashed_values.push hashed
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
#visualize_spin
|
90
|
+
#visualize_hash
|
91
|
+
#visualize_scatter_and_unscatter
|
92
|
+
#visualize_scatter
|
93
|
+
#visualize_swapper_map
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class ScatterSwap
|
2
|
+
# This is the hashing function behind ObfuscateId.
|
3
|
+
# https://github.com/namick/obfuscate_id
|
4
|
+
#
|
5
|
+
# Designing a hash function is a bit of a black art and
|
6
|
+
# being that I don't have math background, I must resort
|
7
|
+
# to this simplistic swaping and scattering of array elements.
|
8
|
+
#
|
9
|
+
# After writing this and reading/learning some elemental hashing techniques,
|
10
|
+
# I realize this library is what is known as a Minimal perfect hash function:
|
11
|
+
# http://en.wikipedia.org/wiki/Perfect_hash_function#Minimal_perfect_hash_function
|
12
|
+
#
|
13
|
+
# I welcome all improvements :-)
|
14
|
+
#
|
15
|
+
# If you have some comments or suggestions, please contact me on github
|
16
|
+
# https://github.com/namick
|
17
|
+
#
|
18
|
+
# - nathan amick
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# This library is built for integers that can be expressed with 10 digits:
|
22
|
+
# It zero pads smaller numbers... so the number one is expressed with:
|
23
|
+
# 0000000001
|
24
|
+
# The biggest number it can deal with is:
|
25
|
+
# 9999999999
|
26
|
+
#
|
27
|
+
# Since we are working with a limited sequential set of input integers, 10 billion,
|
28
|
+
# this algorithm will suffice for simple id obfuscation for many web apps.
|
29
|
+
# The largest value that Ruby on Rails default id, Mysql INT type, is just over 2 billion (2147483647)
|
30
|
+
# which is the same as 2 to the power of 31 minus 1, but considerably less than 10 billion.
|
31
|
+
#
|
32
|
+
# ScatterSwap is an integer hash function designed to have:
|
33
|
+
# - zero collisions ( http://en.wikipedia.org/wiki/Perfect_hash_function )
|
34
|
+
# - achieve avalanche ( http://en.wikipedia.org/wiki/Avalanche_effect )
|
35
|
+
# - reversable
|
36
|
+
#
|
37
|
+
# We do that by combining two distinct strategies.
|
38
|
+
#
|
39
|
+
# 1. Scattering - whereby we take the whole number, slice it up into 10 digits
|
40
|
+
# and rearange their places, yet retaining the same 10 digits. This allows
|
41
|
+
# us to preserve the sum of all the digits, regardless of order. This sum acts
|
42
|
+
# as a key to reverse this scattering effect.
|
43
|
+
#
|
44
|
+
# 2. Swapping - when dealing with many sequential numbers that we don't want
|
45
|
+
# to look similar, scattering wont do us much good because so many of the
|
46
|
+
# digits are the same; it deoesn't help to scatter 9 zeros around, so we need
|
47
|
+
# to swap out each of those zeros for something else.. something different
|
48
|
+
# for each place in the 10 digit array; for this, we need a map so that we
|
49
|
+
# can reverse it.
|
50
|
+
|
51
|
+
# Convience class method pointing to the instance method
|
52
|
+
def self.hash(plain_integer, spin = 0)
|
53
|
+
new(plain_integer, spin).hash
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convience class method pointing to the instance method
|
57
|
+
def self.reverse_hash(hashed_integer, spin = 0)
|
58
|
+
new(hashed_integer, spin).reverse_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(original_integer, spin = 0)
|
62
|
+
@original_integer = original_integer
|
63
|
+
@spin = spin
|
64
|
+
zero_pad = original_integer.to_s.rjust(10, '0')
|
65
|
+
@working_array = zero_pad.split("").collect {|d| d.to_i}
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_accessor :working_array
|
69
|
+
|
70
|
+
# obfuscates an integer up to 10 digits in length
|
71
|
+
def hash
|
72
|
+
swap
|
73
|
+
scatter
|
74
|
+
completed_string
|
75
|
+
end
|
76
|
+
|
77
|
+
# de-obfuscates an integer
|
78
|
+
def reverse_hash
|
79
|
+
unscatter
|
80
|
+
unswap
|
81
|
+
completed_string
|
82
|
+
end
|
83
|
+
|
84
|
+
def completed_string
|
85
|
+
@working_array.join
|
86
|
+
end
|
87
|
+
|
88
|
+
# We want a unique map for each place in the original number
|
89
|
+
def swapper_map(index)
|
90
|
+
array = (0..9).to_a
|
91
|
+
10.times.collect.with_index do |i|
|
92
|
+
array.rotate!(index + i ^ spin).pop
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Using a unique map for each of the ten places,
|
97
|
+
# we swap out one number for another
|
98
|
+
def swap
|
99
|
+
@working_array = @working_array.collect.with_index do |digit, index|
|
100
|
+
swapper_map(index)[digit]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Reverse swap
|
105
|
+
def unswap
|
106
|
+
@working_array = @working_array.collect.with_index do |digit, index|
|
107
|
+
swapper_map(index).rindex(digit)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Rearrange the order of each digit in a reversable way by using the
|
112
|
+
# sum of the digits (which doesn't change regardless of order)
|
113
|
+
# as a key to record how they were scattered
|
114
|
+
def scatter
|
115
|
+
sum_of_digits = @working_array.inject(:+).to_i
|
116
|
+
@working_array = 10.times.collect do
|
117
|
+
@working_array.rotate!(spin ^ sum_of_digits).pop
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Reverse the scatter
|
122
|
+
def unscatter
|
123
|
+
scattered_array = @working_array
|
124
|
+
sum_of_digits = scattered_array.inject(:+).to_i
|
125
|
+
@working_array = []
|
126
|
+
@working_array.tap do |unscatter|
|
127
|
+
10.times do
|
128
|
+
unscatter.push scattered_array.pop
|
129
|
+
unscatter.rotate! (sum_of_digits ^ spin) * -1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Add some spice so that different apps can have differently mapped hashes
|
135
|
+
def spin
|
136
|
+
@spin || 0
|
137
|
+
end
|
138
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: obfuscate_id
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Amick
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-12 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &9066640 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *9066640
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sqlite3
|
27
|
+
requirement: &9063100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *9063100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec-rails
|
38
|
+
requirement: &9061600 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *9061600
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: capybara
|
49
|
+
requirement: &9058580 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *9058580
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: guard-rspec
|
60
|
+
requirement: &9057040 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *9057040
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-spork
|
71
|
+
requirement: &9055460 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *9055460
|
80
|
+
description: ObfuscateId is a simple Ruby on Rails plugin that hides your seqential
|
81
|
+
Active Record ids. Although having nothing to do with security, it can be used
|
82
|
+
to make database record id information non-obvious.
|
83
|
+
email:
|
84
|
+
- github@nathanamick.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- lib/tasks/obfuscate_id_tasks.rake
|
90
|
+
- lib/obfuscate_id/scatter_swap.rb
|
91
|
+
- lib/obfuscate_id/run_scatter_swap.rb
|
92
|
+
- lib/obfuscate_id/version.rb
|
93
|
+
- lib/obfuscate_id.rb
|
94
|
+
- MIT-LICENSE
|
95
|
+
- Rakefile
|
96
|
+
- README.md
|
97
|
+
homepage: ''
|
98
|
+
licenses: []
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
hash: -372583255443185690
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
segments:
|
119
|
+
- 0
|
120
|
+
hash: -372583255443185690
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.8.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: A simple Rails plugin that lightly masks seqential ActiveRecord ids
|
127
|
+
test_files: []
|