idy 0.1.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE +21 -0
- data/README.md +109 -0
- data/lib/idy.rb +9 -0
- data/lib/idy/extension.rb +83 -0
- data/lib/idy/version.rb +5 -0
- data/spec/lib/idy/extension/find_by_spec.rb +13 -0
- data/spec/lib/idy/extension/find_spec.rb +74 -0
- data/spec/lib/idy/extension/idy_decode_spec.rb +37 -0
- data/spec/lib/idy/extension/idy_default_salt_spec.rb +11 -0
- data/spec/lib/idy/extension/idy_encode_spec.rb +50 -0
- data/spec/lib/idy/extension/idy_options_spec.rb +29 -0
- data/spec/lib/idy/extension/idy_spec.rb +11 -0
- data/spec/lib/idy/extension/lock_spec.rb +13 -0
- data/spec/lib/idy/extension/options_spec.rb +23 -0
- data/spec/lib/idy/extension/salt_spec.rb +23 -0
- data/spec/lib/idy/extension/to_param_spec.rb +51 -0
- data/spec/rails_helper.rb +27 -0
- data/spec/support/common.rb +11 -0
- data/spec/support/database_cleaner.rb +21 -0
- data/spec/support/db/migrate/create_tables.rb +29 -0
- data/spec/support/migrate.rb +3 -0
- data/spec/support/models/abcdefghijklm.rb +4 -0
- data/spec/support/models/article.rb +7 -0
- data/spec/support/models/clean.rb +4 -0
- data/spec/support/models/comment.rb +7 -0
- data/spec/support/models/post.rb +5 -0
- data/spec/support/models/user.rb +4 -0
- metadata +225 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b9e139f9dd8d185f4c523382f5a7e10e2ab0f8f
|
4
|
+
data.tar.gz: 1f99aa90fa690f9d926d063df79c55a9f775faee
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7c742d70263a6f7579cfb4e9782ee28307831b07a5400ff01e2c251262d0ab66f6ed391a46f87b66d364c5704b3b167883a4839a1df21a0cad5fb1e544007c27
|
7
|
+
data.tar.gz: 850388e0499f9030b2ac4b8daa203eec2bb973c8587e7d8d3330292d74490c8df15a58369c405fac13e5bf40cc08ad3184fdda793c4c8fc932ebe6e2739ebb4c
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Washington Botelho
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Idy
|
2
|
+
|
3
|
+
[](https://travis-ci.org/wbotelhos/idy)
|
4
|
+
[](https://badge.fury.io/rb/idy)
|
5
|
+
|
6
|
+
An ID obfuscator for ActiveRecord.
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
Do not let your users knows about your IDs:
|
11
|
+
|
12
|
+
- IDs can make hacker's life easier for a sequential attack;
|
13
|
+
- IDs can make crawler's life easier for a sequential scan;
|
14
|
+
- With few records on your database it can seem that your business is weak;
|
15
|
+
- With many records on your database it can call attention of people.
|
16
|
+
|
17
|
+
*Make it clean, make it lean, make it hidden.*
|
18
|
+
|
19
|
+
`http://example.com/articles/1` -> `http://example.com/articles/My`
|
20
|
+
|
21
|
+
It uses [Hashids](http://hashids.org/ruby) to make it pretty.
|
22
|
+
|
23
|
+
## install
|
24
|
+
|
25
|
+
Add the following code on your `Gemfile` and run `bundle install`:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
gem 'idy'
|
29
|
+
```
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
On an `ActiveRecord` model, just add `idy` callback:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
class Article < ApplicationRecord
|
37
|
+
idy
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
Try to call on your model the obfuscated ID:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
Article.new(id: 1).idy
|
45
|
+
# My
|
46
|
+
```
|
47
|
+
|
48
|
+
It will build you Rals URL with that ID too:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
Article.new(id: 1).to_param
|
52
|
+
# localhost:3000/articles/My
|
53
|
+
```
|
54
|
+
|
55
|
+
## Security
|
56
|
+
|
57
|
+
Idy is not for encryption, it is about obfuscation.
|
58
|
+
If you want a *unbreakable* hash, it is not for you.
|
59
|
+
|
60
|
+
## Collision
|
61
|
+
|
62
|
+
To avoid two differents models to generates the same hash for the same ID,
|
63
|
+
by default, the class name is used as a [Salt](https://en.wikipedia.org/wiki/Salt_(cryptography).
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
Article.new(id: 1).idy
|
67
|
+
# My
|
68
|
+
|
69
|
+
User.new(id: 1).idy
|
70
|
+
# ex
|
71
|
+
```
|
72
|
+
|
73
|
+
## Salt
|
74
|
+
|
75
|
+
You can provide you own:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Article < ApplicationRecord
|
79
|
+
idy salt: 's3cr3t'
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
Article.new(id: 1).idy
|
85
|
+
# 9A
|
86
|
+
```
|
87
|
+
|
88
|
+
## Find
|
89
|
+
|
90
|
+
Since you add the `idy` callback to your model, `find` method will be decorated:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
Article.find('My').id
|
94
|
+
# 1
|
95
|
+
```
|
96
|
+
|
97
|
+
Keep in mind that if you have some internal code, that you cannot change,
|
98
|
+
using `find`, the hash version of the id, `idy`, will be mandatory to correct find the record.
|
99
|
+
|
100
|
+
## Inspiration
|
101
|
+
|
102
|
+
It was inpired and improved from:
|
103
|
+
|
104
|
+
- [obfuscate_id](https://github.com/namick/obfuscate_id)
|
105
|
+
- [hashids_uri](https://github.com/danieldraper/hashids_uri)
|
106
|
+
|
107
|
+
## Love it!
|
108
|
+
|
109
|
+
Via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=X8HEP2878NDEG&item_name=idy) or [Gratipay](https://gratipay.com/~wbotelhos). Thanks! (:
|
data/lib/idy.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Idy
|
4
|
+
module Extension
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
def idy
|
9
|
+
self.class.idy_encode id
|
10
|
+
end
|
11
|
+
|
12
|
+
def idy_options
|
13
|
+
self.class.idy_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def salt
|
17
|
+
self.class.salt
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_param
|
21
|
+
return super unless self.class.respond_to?(:idy?)
|
22
|
+
|
23
|
+
self.class.idy_encode id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def find(*args)
|
29
|
+
query = [args.first].flatten
|
30
|
+
|
31
|
+
if try(:idy?)
|
32
|
+
if query.size == 1
|
33
|
+
super idy_decode(query[0].to_s) || query[0]
|
34
|
+
else
|
35
|
+
super [query].flatten.map { |hash| idy_decode hash }
|
36
|
+
end
|
37
|
+
else
|
38
|
+
super [query].flatten.size == 1 ? query[0] : query
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def idy(options = {})
|
43
|
+
@options = options.reverse_merge(salt: idy_default_salt)
|
44
|
+
|
45
|
+
define_singleton_method(:idy?) { true }
|
46
|
+
end
|
47
|
+
|
48
|
+
def idy_decode(hash, salt: self.salt)
|
49
|
+
encoder(salt).decode(hash).first
|
50
|
+
end
|
51
|
+
|
52
|
+
def idy_default_salt
|
53
|
+
alphabet = Array('a'..'z')
|
54
|
+
|
55
|
+
indexes = name.downcase.split('').map do |char|
|
56
|
+
alphabet.index(char) + 1
|
57
|
+
end
|
58
|
+
|
59
|
+
indexes.shift(10).join
|
60
|
+
end
|
61
|
+
|
62
|
+
def idy_encode(id, salt: self.salt)
|
63
|
+
return unless id
|
64
|
+
|
65
|
+
encoder(salt).encode id
|
66
|
+
end
|
67
|
+
|
68
|
+
def idy_options
|
69
|
+
@options || { salt: idy_default_salt }
|
70
|
+
end
|
71
|
+
|
72
|
+
def salt
|
73
|
+
idy_options[:salt]
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def encoder(salt)
|
79
|
+
Hashids.new salt.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/idy/version.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe Article, '.find_by' do
|
6
|
+
subject { described_class.create title: 'title' }
|
7
|
+
|
8
|
+
it 'works with normal id' do
|
9
|
+
record = described_class.find_by(id: subject.id)
|
10
|
+
|
11
|
+
expect(subject).to eq record
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe Article do
|
6
|
+
context 'on reload' do
|
7
|
+
subject { described_class.create id: 42, title: 'title' }
|
8
|
+
|
9
|
+
it 'reloads' do
|
10
|
+
record = described_class.find(subject.to_param)
|
11
|
+
|
12
|
+
record.update_attribute :title, 'title.updated'
|
13
|
+
|
14
|
+
expect(subject.title).to eq 'title'
|
15
|
+
expect(subject.reload.title).to eq 'title.updated'
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'while locking' do
|
19
|
+
it 'does not throw an error' do
|
20
|
+
expect(-> { subject.lock! }).not_to raise_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'finding one record as id' do
|
26
|
+
subject { described_class.find record.id }
|
27
|
+
|
28
|
+
let!(:record) { described_class.create id: 42, title: 'title-1' }
|
29
|
+
|
30
|
+
specify { expect(subject).to eq record }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'finding one record as idy' do
|
34
|
+
subject { described_class.find record.to_param }
|
35
|
+
|
36
|
+
let!(:record) { described_class.create id: 42, title: 'title-1' }
|
37
|
+
|
38
|
+
specify { expect(subject).to eq record }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'finding multiple records' do
|
42
|
+
subject { described_class.find [record_1.to_param, record_2.to_param] }
|
43
|
+
|
44
|
+
let!(:record_1) { described_class.create id: 42, title: 'title-1' }
|
45
|
+
let!(:record_2) { described_class.create id: 1 , title: 'title-2' }
|
46
|
+
|
47
|
+
it 'finds all' do
|
48
|
+
expect(subject).to eq [record_1, record_2]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'finding via has_many' do
|
53
|
+
let!(:article) { described_class.create }
|
54
|
+
let!(:comment) { Comment.create article: article }
|
55
|
+
|
56
|
+
specify { expect(article.comments.find(comment.id)).to eq comment }
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'finding a class with no callback declared' do
|
60
|
+
let!(:record) { Clean.create }
|
61
|
+
|
62
|
+
context 'of one record' do
|
63
|
+
specify { expect(Clean.find(record.id)).to eq record }
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'of multiple record' do
|
67
|
+
let!(:record_2) { Clean.create }
|
68
|
+
|
69
|
+
specify do
|
70
|
+
expect(Clean.find([record.id, record_2.id])).to eq [record, record_2]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe '#idy_decode' do
|
6
|
+
context 'with no given salt' do
|
7
|
+
it 'undos the obfuscation of id with default class salt' do
|
8
|
+
expect(Article.idy_decode('My')).to eq 1
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'with empty salt' do
|
13
|
+
let!(:salt) { '' }
|
14
|
+
|
15
|
+
it 'undos the obfuscation of id with given salt' do
|
16
|
+
expect(Article.idy_decode('jR', salt: salt)).to eq 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with salt' do
|
21
|
+
context 'as string' do
|
22
|
+
let!(:salt) { 'salt' }
|
23
|
+
|
24
|
+
it 'undos the obfuscation of id with given salt' do
|
25
|
+
expect(Article.idy_decode('XG', salt: salt)).to eq 1
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'as number' do
|
30
|
+
let!(:salt) { 1 }
|
31
|
+
|
32
|
+
it 'undos the obfuscation of id with given salt as string' do
|
33
|
+
expect(Article.idy_decode('kL', salt: 1)).to eq 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe '#idy_default_salt' do
|
6
|
+
context 'when class name has a big length' do
|
7
|
+
it 'is bases on the first 10 class letter position index on alphabet' do
|
8
|
+
expect(Abcdefghijklm.idy_default_salt).to eq '12345678910'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe '#idy_encode' do
|
6
|
+
context 'with no given salt' do
|
7
|
+
let!(:model) { Article.new id: 1 }
|
8
|
+
|
9
|
+
it 'obfuscates the id with default class salt' do
|
10
|
+
expect(model.class.idy_encode(model.id)).to eq 'My'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'with empty salt' do
|
15
|
+
let!(:model) { Article.new id: 1 }
|
16
|
+
let!(:salt) { '' }
|
17
|
+
|
18
|
+
it 'obfuscates the id with empty salt' do
|
19
|
+
expect(model.class.idy_encode(model.id, salt: salt)).to eq 'jR'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'with salt' do
|
24
|
+
let!(:model) { Article.new id: 1 }
|
25
|
+
|
26
|
+
context 'as string' do
|
27
|
+
let!(:salt) { 'salt' }
|
28
|
+
|
29
|
+
it 'obfuscates the id with given salt' do
|
30
|
+
expect(model.class.idy_encode(model.id, salt: salt)).to eq 'XG'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'as number' do
|
35
|
+
let!(:salt) { 1 }
|
36
|
+
|
37
|
+
it 'obfuscates the id with given salt as string' do
|
38
|
+
expect(model.class.idy_encode(model.id, salt: salt)).to eq 'kL'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'with nil id' do
|
44
|
+
let!(:model) { Article.new }
|
45
|
+
|
46
|
+
it 'returns nil' do
|
47
|
+
expect(model.class.idy_encode(model.id)).to be_nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe ':idy_options' do
|
6
|
+
describe '.idy_options' do
|
7
|
+
context 'when has options' do
|
8
|
+
it 'returns the options' do
|
9
|
+
expect(Comment.new.idy_options).to eq(salt: 'salt')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'when has no options' do
|
14
|
+
it 'returns an default one' do
|
15
|
+
expect(Clean.new.idy_options).to eq(salt: clean_default_salt)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#idy_options' do
|
21
|
+
before do
|
22
|
+
allow(Clean).to receive(:idy_options) { :idy_options }
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'delegates to class method' do
|
26
|
+
expect(Clean.new.idy_options).to eq :idy_options
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe Article, '.lock!' do
|
6
|
+
subject { described_class.create title: 'title' }
|
7
|
+
|
8
|
+
it 'works' do
|
9
|
+
record = described_class.find(subject.to_param)
|
10
|
+
|
11
|
+
expect { record.lock! }.not_to raise_error
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe '.idy_options' do
|
6
|
+
context 'when callback is not given' do
|
7
|
+
it 'returns a default options with a salt generated based on model name' do
|
8
|
+
expect(Clean.new.idy_options).to eq(salt: clean_default_salt)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'when options is not given' do
|
13
|
+
it 'returns a default options with a salt generated based on model name' do
|
14
|
+
expect(Article.idy_options).to eq(salt: article_default_salt)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when salt is given' do
|
19
|
+
it 'returns a default options with a salt equal the given one' do
|
20
|
+
expect(Comment.idy_options).to eq(salt: 'salt')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe ':salt' do
|
6
|
+
describe '#salt' do
|
7
|
+
before do
|
8
|
+
allow(Clean).to receive(:idy_options) { { salt: :salty } }
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'fetchs the salt options' do
|
12
|
+
expect(Clean.salt).to eq(:salty)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.salt' do
|
17
|
+
before { allow(Clean).to receive(:salt) { :salt } }
|
18
|
+
|
19
|
+
it 'delegates to class method' do
|
20
|
+
expect(Clean.new.salt).to eq :salt
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
RSpec.describe '.to_param' do
|
6
|
+
context 'when object does not acts as idy' do
|
7
|
+
subject { Clean.new id: 1 }
|
8
|
+
|
9
|
+
it 'behaves as default' do
|
10
|
+
expect(subject.to_param).to eq '1'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when object acts as idy' do
|
15
|
+
context 'with no given salt' do
|
16
|
+
let!(:model_1) { Article.new id: 1 }
|
17
|
+
|
18
|
+
it 'generates a hash' do
|
19
|
+
expect(model_1.to_param).to eq 'My'
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with comparison' do
|
23
|
+
let!(:model_2) { Post.new }
|
24
|
+
|
25
|
+
context 'with other object with same id' do
|
26
|
+
before { model_2.id = 1 }
|
27
|
+
|
28
|
+
it 'generates different hash' do
|
29
|
+
expect(model_1.to_param).not_to eq model_2.to_param
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when object is not persisted' do
|
35
|
+
context 'and has no id' do
|
36
|
+
subject { Article.new }
|
37
|
+
|
38
|
+
specify { expect(subject.to_param).to be_nil }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'and has id' do
|
42
|
+
subject { Article.new id: 1 }
|
43
|
+
|
44
|
+
it 'generates a hash' do
|
45
|
+
expect(model_1.to_param).to eq 'My'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ENV['RAILS_ENV'] ||= 'test'
|
4
|
+
|
5
|
+
require 'active_record/railtie'
|
6
|
+
require 'idy'
|
7
|
+
require 'pry-byebug'
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection adapter: :sqlite3, database: ':memory:'
|
10
|
+
|
11
|
+
Dir[File.expand_path('support/**/*.rb', __dir__)].each { |file| require file }
|
12
|
+
|
13
|
+
def article_default_salt
|
14
|
+
'1182093125'
|
15
|
+
end
|
16
|
+
|
17
|
+
def clean_default_salt
|
18
|
+
'3125114'
|
19
|
+
end
|
20
|
+
|
21
|
+
def comment_default_salt
|
22
|
+
''
|
23
|
+
end
|
24
|
+
|
25
|
+
def user_default_salt
|
26
|
+
'1182093125'
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'database_cleaner'
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.before :suite do
|
7
|
+
DatabaseCleaner.strategy = :transaction
|
8
|
+
|
9
|
+
DatabaseCleaner.clean_with :transaction
|
10
|
+
end
|
11
|
+
|
12
|
+
config.before :each do
|
13
|
+
DatabaseCleaner.start
|
14
|
+
end
|
15
|
+
|
16
|
+
config.around do |spec|
|
17
|
+
DatabaseCleaner.cleaning do
|
18
|
+
spec.run
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateTables < ActiveRecord::Migration[5.0]
|
4
|
+
def change
|
5
|
+
create_table :abcdefghijklms do |t|
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :articles do |t|
|
9
|
+
t.string :title
|
10
|
+
end
|
11
|
+
|
12
|
+
create_table :cleans do |t|
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :comments do |t|
|
16
|
+
t.string :body
|
17
|
+
|
18
|
+
t.references :article, index: true, foreign_key: true
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :posts do |t|
|
22
|
+
t.string :title
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :users do |t|
|
26
|
+
t.string :name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: idy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Washington Botelho
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashids
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '6'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '5'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '6'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: database_cleaner
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: guard-rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec-rails
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rubocop-rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: rubocop
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: sqlite3
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: pry-byebug
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
description: An ID obfuscator for ActiveRecord.
|
146
|
+
email: wbotelhos@gmail.com
|
147
|
+
executables: []
|
148
|
+
extensions: []
|
149
|
+
extra_rdoc_files: []
|
150
|
+
files:
|
151
|
+
- CHANGELOG.md
|
152
|
+
- LICENSE
|
153
|
+
- README.md
|
154
|
+
- lib/idy.rb
|
155
|
+
- lib/idy/extension.rb
|
156
|
+
- lib/idy/version.rb
|
157
|
+
- spec/lib/idy/extension/find_by_spec.rb
|
158
|
+
- spec/lib/idy/extension/find_spec.rb
|
159
|
+
- spec/lib/idy/extension/idy_decode_spec.rb
|
160
|
+
- spec/lib/idy/extension/idy_default_salt_spec.rb
|
161
|
+
- spec/lib/idy/extension/idy_encode_spec.rb
|
162
|
+
- spec/lib/idy/extension/idy_options_spec.rb
|
163
|
+
- spec/lib/idy/extension/idy_spec.rb
|
164
|
+
- spec/lib/idy/extension/lock_spec.rb
|
165
|
+
- spec/lib/idy/extension/options_spec.rb
|
166
|
+
- spec/lib/idy/extension/salt_spec.rb
|
167
|
+
- spec/lib/idy/extension/to_param_spec.rb
|
168
|
+
- spec/rails_helper.rb
|
169
|
+
- spec/support/common.rb
|
170
|
+
- spec/support/database_cleaner.rb
|
171
|
+
- spec/support/db/migrate/create_tables.rb
|
172
|
+
- spec/support/migrate.rb
|
173
|
+
- spec/support/models/abcdefghijklm.rb
|
174
|
+
- spec/support/models/article.rb
|
175
|
+
- spec/support/models/clean.rb
|
176
|
+
- spec/support/models/comment.rb
|
177
|
+
- spec/support/models/post.rb
|
178
|
+
- spec/support/models/user.rb
|
179
|
+
homepage: https://github.com/wbotelhos/idy
|
180
|
+
licenses:
|
181
|
+
- MIT
|
182
|
+
metadata: {}
|
183
|
+
post_install_message:
|
184
|
+
rdoc_options: []
|
185
|
+
require_paths:
|
186
|
+
- lib
|
187
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
requirements: []
|
198
|
+
rubyforge_project:
|
199
|
+
rubygems_version: 2.6.11
|
200
|
+
signing_key:
|
201
|
+
specification_version: 4
|
202
|
+
summary: An ID obfuscator for ActiveRecord.
|
203
|
+
test_files:
|
204
|
+
- spec/lib/idy/extension/find_by_spec.rb
|
205
|
+
- spec/lib/idy/extension/find_spec.rb
|
206
|
+
- spec/lib/idy/extension/idy_decode_spec.rb
|
207
|
+
- spec/lib/idy/extension/idy_default_salt_spec.rb
|
208
|
+
- spec/lib/idy/extension/idy_encode_spec.rb
|
209
|
+
- spec/lib/idy/extension/idy_options_spec.rb
|
210
|
+
- spec/lib/idy/extension/idy_spec.rb
|
211
|
+
- spec/lib/idy/extension/lock_spec.rb
|
212
|
+
- spec/lib/idy/extension/options_spec.rb
|
213
|
+
- spec/lib/idy/extension/salt_spec.rb
|
214
|
+
- spec/lib/idy/extension/to_param_spec.rb
|
215
|
+
- spec/rails_helper.rb
|
216
|
+
- spec/support/common.rb
|
217
|
+
- spec/support/database_cleaner.rb
|
218
|
+
- spec/support/db/migrate/create_tables.rb
|
219
|
+
- spec/support/migrate.rb
|
220
|
+
- spec/support/models/abcdefghijklm.rb
|
221
|
+
- spec/support/models/article.rb
|
222
|
+
- spec/support/models/clean.rb
|
223
|
+
- spec/support/models/comment.rb
|
224
|
+
- spec/support/models/post.rb
|
225
|
+
- spec/support/models/user.rb
|