tokens 0.1.0 → 0.2.0.beta.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.
- data/README.rdoc +1 -1
- data/Rakefile +1 -1
- data/lib/tokens/token.rb +7 -7
- data/lib/tokens/version.rb +1 -1
- data/lib/tokens.rb +112 -96
- data/spec/schema.rb +11 -9
- data/spec/spec_helper.rb +3 -17
- data/spec/tokens_spec.rb +6 -6
- metadata +17 -10
- data/init.rb +0 -1
- data/lib/tokens/string_ext.rb +0 -7
data/README.rdoc
CHANGED
@@ -78,7 +78,7 @@ Run migrations with <tt>rake db:migrate</tt>. Add the method call
|
|
78
78
|
User.find_by_token(:activate, "ea2f14aeac40")
|
79
79
|
|
80
80
|
# remove all expired tokens except those with NULL values
|
81
|
-
Token.
|
81
|
+
Token.clean
|
82
82
|
|
83
83
|
# generate a token as string, without saving it
|
84
84
|
User.generate_token
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ begin
|
|
8
8
|
gem.email = "fnando.vieira@gmail.com"
|
9
9
|
gem.homepage = "http://github.com/fnando/has_tokens"
|
10
10
|
gem.authors = ["Nando Vieira"]
|
11
|
-
gem.version = SimplesIdeias::Tokens::Version::STRING
|
11
|
+
gem.version = SimplesIdeias::Tokens::Version::STRING + ".beta.1"
|
12
12
|
gem.summary = "Generate named tokens on your ActiveRecord models."
|
13
13
|
gem.files = FileList["README.rdoc", "init.rb", "{lib,spec,source}/**/*", "Rakefile"]
|
14
14
|
end
|
data/lib/tokens/token.rb
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
class Token < ActiveRecord::Base
|
2
2
|
belongs_to :tokenizable, :polymorphic => true
|
3
|
-
|
3
|
+
|
4
4
|
def hash
|
5
5
|
token
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def to_s
|
9
9
|
hash
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def expired?
|
13
13
|
expires_at && expires_at < Time.now
|
14
14
|
end
|
15
|
-
|
16
|
-
def self.
|
17
|
-
delete_all ["expires_at < ? AND expires_at IS NOT NULL", Time.now]
|
15
|
+
|
16
|
+
def self.clean
|
17
|
+
delete_all ["expires_at < ? AND expires_at IS NOT NULL", Time.now]
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
data/lib/tokens/version.rb
CHANGED
data/lib/tokens.rb
CHANGED
@@ -1,115 +1,131 @@
|
|
1
|
-
|
2
|
-
require "
|
3
|
-
require "tokens/
|
4
|
-
require "tokens/token"
|
5
|
-
|
6
|
-
module SimplesIdeias
|
7
|
-
module Tokens #:nodoc:
|
8
|
-
def self.included(base)
|
9
|
-
base.extend ClassMethods
|
10
|
-
end
|
11
|
-
|
12
|
-
module ClassMethods
|
13
|
-
def has_tokens
|
14
|
-
write_inheritable_attribute(:has_tokens_options, {
|
15
|
-
:token_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s
|
16
|
-
})
|
1
|
+
module Tokens
|
2
|
+
require "tokens/token"
|
3
|
+
require "tokens/version"
|
17
4
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
include SimplesIdeias::Tokens::InstanceMethods
|
22
|
-
end
|
23
|
-
|
24
|
-
def generate_token(seed, size)
|
25
|
-
validity = Proc.new { |token| Token.find(:first, :conditions => {:token => token}).nil? }
|
26
|
-
|
27
|
-
begin
|
28
|
-
seed = Digest::SHA1.hexdigest(seed)
|
29
|
-
token = Digest::SHA1.hexdigest(seed)[0, size]
|
30
|
-
end while !validity.call(token)
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval { extend ClassMethods }
|
7
|
+
end
|
31
8
|
|
32
|
-
|
33
|
-
|
9
|
+
module ClassMethods
|
10
|
+
# Set up model for using tokens.
|
11
|
+
#
|
12
|
+
# class User < ActiveRecord::Base
|
13
|
+
# has_tokens
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
def has_tokens
|
17
|
+
has_many :tokens, :as => :tokenizable, :dependent => :destroy
|
18
|
+
include InstanceMethods
|
19
|
+
end
|
34
20
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
options = {:name => args.first, :token => args.last.to_s}
|
42
|
-
end
|
43
|
-
|
44
|
-
options[:name] = options[:name].to_s
|
45
|
-
options.merge!({:tokenizable_type => has_tokens_options[:token_type]})
|
46
|
-
Token.find(:first, :conditions => options)
|
47
|
-
end
|
21
|
+
# Generate token using seed and size.
|
22
|
+
#
|
23
|
+
# User.generate_token("abc", 10)
|
24
|
+
#
|
25
|
+
def generate_token(seed, size)
|
26
|
+
validity = Proc.new {|token| Token.where(:token => token).first.nil?}
|
48
27
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
return nil unless t
|
54
|
-
t.tokenizable
|
55
|
-
end
|
28
|
+
begin
|
29
|
+
seed = Digest::SHA1.hexdigest(seed)
|
30
|
+
token = Digest::SHA1.hexdigest(seed)[0, size]
|
31
|
+
end while validity[token] == false
|
56
32
|
|
57
|
-
|
58
|
-
# User.find_by_valid_token(:activation, 'abcdefg')
|
59
|
-
def find_by_valid_token(name, token)
|
60
|
-
t = find_token(:name => name.to_s, :token => token)
|
61
|
-
return nil unless t && !t.expired? && t.hash == token
|
62
|
-
t.tokenizable
|
63
|
-
end
|
33
|
+
token
|
64
34
|
end
|
65
35
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
36
|
+
# Find a token
|
37
|
+
#
|
38
|
+
# User.find_token(:activation, 'abcdefg')
|
39
|
+
# User.find_token(:name => activation, :token => 'abcdefg')
|
40
|
+
# User.find_token(:name => activation, :token => 'abcdefg', :tokenizable_id => 1)
|
41
|
+
#
|
42
|
+
def find_token(*args)
|
43
|
+
if args.first.kind_of?(Hash)
|
44
|
+
args.first
|
45
|
+
else
|
46
|
+
options = {
|
47
|
+
:name => args.first,
|
48
|
+
:token => args.last
|
49
|
+
}
|
72
50
|
end
|
73
51
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
self.id,
|
78
|
-
self.class.has_tokens_options[:token_type],
|
79
|
-
name.to_s
|
80
|
-
])
|
81
|
-
end
|
52
|
+
options.merge!(:name => options[:name].to_s, :tokenizable_type => self.name)
|
53
|
+
Token.where(options).include(:tokenizable).first
|
54
|
+
end
|
82
55
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
56
|
+
# Find object by token.
|
57
|
+
#
|
58
|
+
# User.find_by_token(:activation, 'abcdefg')
|
59
|
+
#
|
60
|
+
def find_by_token(name, hash)
|
61
|
+
token = find_token(:name => name.to_s, :token => hash)
|
62
|
+
return nil unless token
|
63
|
+
token.tokenizable
|
64
|
+
end
|
89
65
|
|
90
|
-
|
66
|
+
# Find object by valid token (same name, same hash, not expired).
|
67
|
+
#
|
68
|
+
# User.find_by_valid_token(:activation, 'abcdefg')
|
69
|
+
#
|
70
|
+
def find_by_valid_token(name, hash)
|
71
|
+
token = find_token(:name => name.to_s, :token => hash)
|
72
|
+
return nil if !token || t.expired?
|
73
|
+
t.tokenizable
|
74
|
+
end
|
75
|
+
end
|
91
76
|
|
92
|
-
|
77
|
+
module InstanceMethods
|
78
|
+
# Find a token.
|
79
|
+
#
|
80
|
+
# @user.find_token(:activation, 'abcdefg')
|
81
|
+
#
|
82
|
+
def find_token(name, token)
|
83
|
+
self.class.find_token(
|
84
|
+
:tokenizable_id => self.id,
|
85
|
+
:name => name.to_s, :token => token
|
86
|
+
)
|
87
|
+
end
|
93
88
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
:data => options[:data]
|
99
|
-
)
|
100
|
-
end
|
89
|
+
# Find token by its name.
|
90
|
+
def find_token_by_name(name)
|
91
|
+
self.tokens.find_by_name(name.to_s)
|
92
|
+
end
|
101
93
|
|
102
|
-
|
103
|
-
|
104
|
-
|
94
|
+
# Remove token.
|
95
|
+
#
|
96
|
+
# @user.remove_token(:activate)
|
97
|
+
#
|
98
|
+
def remove_token(name)
|
99
|
+
return if new_record?
|
100
|
+
token = find_token_by_name(name)
|
101
|
+
token && token.destroy
|
102
|
+
end
|
105
103
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
104
|
+
# Add a new token.
|
105
|
+
#
|
106
|
+
# @user.add_token(:api_key, :expires_at => nil)
|
107
|
+
# @user.add_token(:api_key, :size => 20)
|
108
|
+
# @user.add_token(:api_key, :data => data.to_yaml)
|
109
|
+
#
|
110
|
+
def add_token(name, options={})
|
111
|
+
options.reverse_merge!({
|
112
|
+
:expires_at => 2.days.from_now,
|
113
|
+
:size => 12,
|
114
|
+
:data => nil
|
115
|
+
})
|
116
|
+
|
117
|
+
remove_token(name)
|
118
|
+
|
119
|
+
seed = "--#{rand}--#{self.object_id}--#{Time.now}--"
|
120
|
+
|
121
|
+
self.tokens.create(
|
122
|
+
:name => name.to_s,
|
123
|
+
:token => self.class.generate_token(seed, options[:size]),
|
124
|
+
:expires_at => options[:expires_at],
|
125
|
+
:data => options[:data]
|
126
|
+
)
|
111
127
|
end
|
112
128
|
end
|
113
129
|
end
|
114
130
|
|
115
|
-
ActiveRecord::Base.send
|
131
|
+
ActiveRecord::Base.send :include, Tokens
|
data/spec/schema.rb
CHANGED
@@ -2,17 +2,19 @@ ActiveRecord::Schema.define(:version => 0) do
|
|
2
2
|
create_table :users do |t|
|
3
3
|
t.string :name
|
4
4
|
end
|
5
|
-
|
5
|
+
|
6
6
|
create_table :posts do |t|
|
7
7
|
t.string :title
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
create_table :tokens do |t|
|
11
|
-
t.integer
|
12
|
-
t.string
|
13
|
-
t.string
|
14
|
-
t.text
|
15
|
-
t.datetime
|
16
|
-
t.datetime
|
11
|
+
t.integer :tokenizable_id, :null => false
|
12
|
+
t.string :tokenizable_type, :name, :null => false
|
13
|
+
t.string :token, :null => false, :limit => 40
|
14
|
+
t.text :data, :null => true
|
15
|
+
t.datetime :expires_at, :null => true
|
16
|
+
t.datetime :created_at
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
|
+
add_index :tokens, :token, :unique => true
|
20
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,23 +1,9 @@
|
|
1
1
|
$LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "ruby-debug"
|
3
|
+
require "rspec"
|
5
4
|
require "active_record"
|
6
5
|
require "tokens"
|
7
6
|
|
8
|
-
ActiveRecord::Base.establish_connection(:adapter =>
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
9
8
|
|
10
|
-
load(
|
11
|
-
|
12
|
-
class Object
|
13
|
-
def self.unset_class(*args)
|
14
|
-
class_eval do
|
15
|
-
args.each do |klass|
|
16
|
-
eval(klass) rescue nil
|
17
|
-
remove_const(klass) if const_defined?(klass)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
alias :doing :lambda
|
9
|
+
load("schema.rb")
|
data/spec/tokens_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe "has_tokens" do
|
|
21
21
|
|
22
22
|
describe "- token" do
|
23
23
|
it "should be created" do
|
24
|
-
|
24
|
+
expect { @user.add_token(:uid) }.to change(Token, :count)
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should be created for different users" do
|
@@ -101,23 +101,23 @@ describe "has_tokens" do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should have tokens association" do
|
104
|
-
|
104
|
+
expect { @user.tokens }.to_not raise_error
|
105
105
|
end
|
106
106
|
|
107
107
|
it "should remove all expired tokens" do
|
108
|
-
|
108
|
+
expect {
|
109
109
|
%w(uid activation_code reset_password_code).each do |name|
|
110
110
|
@user.add_token(name, :expires_at => 3.days.ago)
|
111
111
|
end
|
112
|
-
}.
|
112
|
+
}.to change(Token, :count).by(3)
|
113
113
|
|
114
114
|
Token.delete_expired.should == 3
|
115
115
|
end
|
116
116
|
|
117
117
|
it "should generate token without saving it" do
|
118
|
-
|
118
|
+
expect {
|
119
119
|
User.generate_token(Time.now.to_s, 32)
|
120
|
-
}.
|
120
|
+
}.to_not change(Token, :count)
|
121
121
|
end
|
122
122
|
|
123
123
|
it "should generate token with custom size" do
|
metadata
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tokens
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 62196353
|
5
|
+
prerelease: true
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
+
- 2
|
8
9
|
- 0
|
9
|
-
|
10
|
+
- beta
|
11
|
+
- 1
|
12
|
+
version: 0.2.0.beta.1
|
10
13
|
platform: ruby
|
11
14
|
authors:
|
12
15
|
- Nando Vieira
|
@@ -14,7 +17,7 @@ autorequire:
|
|
14
17
|
bindir: bin
|
15
18
|
cert_chain: []
|
16
19
|
|
17
|
-
date: 2010-07-
|
20
|
+
date: 2010-07-27 00:00:00 -03:00
|
18
21
|
default_executable:
|
19
22
|
dependencies: []
|
20
23
|
|
@@ -29,9 +32,7 @@ extra_rdoc_files:
|
|
29
32
|
files:
|
30
33
|
- README.rdoc
|
31
34
|
- Rakefile
|
32
|
-
- init.rb
|
33
35
|
- lib/tokens.rb
|
34
|
-
- lib/tokens/string_ext.rb
|
35
36
|
- lib/tokens/token.rb
|
36
37
|
- lib/tokens/version.rb
|
37
38
|
- spec/schema.rb
|
@@ -47,23 +48,29 @@ rdoc_options:
|
|
47
48
|
require_paths:
|
48
49
|
- lib
|
49
50
|
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
50
52
|
requirements:
|
51
53
|
- - ">="
|
52
54
|
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
53
56
|
segments:
|
54
57
|
- 0
|
55
58
|
version: "0"
|
56
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
57
61
|
requirements:
|
58
|
-
- - "
|
62
|
+
- - ">"
|
59
63
|
- !ruby/object:Gem::Version
|
64
|
+
hash: 25
|
60
65
|
segments:
|
61
|
-
-
|
62
|
-
|
66
|
+
- 1
|
67
|
+
- 3
|
68
|
+
- 1
|
69
|
+
version: 1.3.1
|
63
70
|
requirements: []
|
64
71
|
|
65
72
|
rubyforge_project:
|
66
|
-
rubygems_version: 1.3.
|
73
|
+
rubygems_version: 1.3.7
|
67
74
|
signing_key:
|
68
75
|
specification_version: 3
|
69
76
|
summary: Generate named tokens on your ActiveRecord models.
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'tokens'
|