active_model_otp 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZjdjOTMxYzkxNjI1MGM0ODdiZmNkZmFiYTZiMjBlZjc4ZTQzMjg2Mw==
5
- data.tar.gz: !binary |-
6
- ZTQ4OGJlNTQzOTViZWEzNDU1MWU1YmQ3Y2Q5Njc3ZDQ0ZjdmMDVkYQ==
2
+ SHA1:
3
+ metadata.gz: 9d9aedb666900aee840275449fcdb4c2fb912c27
4
+ data.tar.gz: de9ef98a499709f05a3a836cd50242c74f8b1fdf
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- YWIyZDViZGE0YWRhYjc2M2YyZjRkYWVhMDI3NjA4YjgxMzRhY2E1MjNkOWM4
10
- MmE5YjZlOTlhYmVkMDhkZjNjZjMzOTYzNzkzNTQ0ODZjMGEzOTRjZTc1OGNj
11
- NDYwNDRiNmEzNmNjZWJhYTQxNzdhNzE2MzBjYzVhNjFhMzAzMWQ=
12
- data.tar.gz: !binary |-
13
- YjdkNDlkYmRjNWM1MTRlZDQzZTMwNzFkZGE4OGMwMzU5NmQ1YWExMDY4YTA2
14
- NTMwOTgwYWE5NjdkM2M1MzdiMDc3MGZhMWM0YWUzMDA2NDFlNDFmNWM3ZTlk
15
- Y2ViODliODQ4YzQxYmY1Y2UyNWNiYjIzY2QwMDQzZDllNWFhYjQ=
6
+ metadata.gz: bc0e46abcdae3948c4ea3bf51d92848ecc887d83efb611f7828b830d45f4d2372e0aa45d1c229e627de6e5d404c1ebb626d4c130ed6a3f14980cae6de33da122
7
+ data.tar.gz: 302bcfde4c0b3d33355cf44ed9b8896a1f83c615c3fafdc9c741ae171955ab78197e5de9b31ac0a4cc7d60fd801c2718c08949f7fc724e8b821e852d10a67179
data/.travis.yml CHANGED
@@ -1,11 +1,10 @@
1
1
  rvm:
2
2
  - 1.9.3
3
3
  - 2.0.0
4
+ - 2.1
4
5
  matrix:
5
6
  include:
6
7
  - rvm: jruby
7
8
  env: JRUBY_OPTS="--1.9 --server -Xcext.enabled=true"
8
- - rvm: jruby-head
9
- env: JRUBY_OPTS="--1.9 --server -Xcext.enabled=true"
10
9
  notifications:
11
10
  email: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,4 @@
1
+ #unreleased
1
2
  #v1.0.0
2
3
  - Avoid overriding predefined otp_column value when initializing resource (Ilan Stern) https://github.com/heapsource/active_model_otp/pull/10
3
4
  - Pad OTP codes with less than 6 digits (Johan Brissmyr) https://github.com/heapsource/active_model_otp/pull/7
data/README.md CHANGED
@@ -42,6 +42,14 @@ Note: If you're adding this to an existing user model you'll need to generate *o
42
42
  User.all.each { |user| user.update_attribute(:otp_secret_key, ROTP::Base32.random_base32) }
43
43
  ```
44
44
 
45
+ For use a custom column for store the secret key field you can us the column_name option
46
+
47
+ ```ruby
48
+ class User < ActiveRecord::Base
49
+ has_one_time_password column_name: :my_otp_secret_column
50
+ end
51
+ ```
52
+
45
53
 
46
54
  ##Usage
47
55
 
@@ -133,7 +141,7 @@ puts "Current code #{user.otp_code}"
133
141
  - [Generate QR code with rqrcode gem](https://github.com/heapsource/active_model_otp/wiki/Generate-QR-code-with-rqrcode-gem)
134
142
  - Generating QR Code with Google Charts API
135
143
  - [Sendind code via email with Twilio](https://github.com/heapsource/active_model_otp/wiki/Send-code-via-Twilio-SMS)
136
- - Using with Mongoid
144
+ - [Using with Mongoid](https://github.com/heapsource/active_model_otp/wiki/Using-with-Mongoid)
137
145
 
138
146
  ## Contributing
139
147
 
@@ -23,5 +23,5 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.3"
25
25
  spec.add_development_dependency "rake"
26
- spec.add_development_dependency "minitest"
26
+ spec.add_development_dependency "minitest", "~> 5.4.2"
27
27
  end
@@ -3,14 +3,18 @@ module ActiveModel
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  module ClassMethods
6
+
6
7
  def has_one_time_password(options = {})
7
8
 
8
9
  cattr_accessor :otp_column_name
10
+ class_attribute :otp_digits
11
+
9
12
  self.otp_column_name = (options[:column_name] || "otp_secret_key").to_s
13
+ self.otp_digits = options[:length] || 6
10
14
 
11
15
  include InstanceMethodsOnActivation
12
16
 
13
- before_create { self.otp_column ||= ROTP::Base32.random_base32 }
17
+ before_create { self.otp_regenerate_secret if !self.otp_column}
14
18
 
15
19
  if respond_to?(:attributes_protected_by_default)
16
20
  def self.attributes_protected_by_default #:nodoc:
@@ -21,8 +25,12 @@ module ActiveModel
21
25
  end
22
26
 
23
27
  module InstanceMethodsOnActivation
28
+ def otp_regenerate_secret
29
+ self.otp_column = ROTP::Base32.random_base32
30
+ end
31
+
24
32
  def authenticate_otp(code, options = {})
25
- totp = ROTP::TOTP.new(self.otp_column)
33
+ totp = ROTP::TOTP.new(self.otp_column, {digits: self.otp_digits})
26
34
  if drift = options[:drift]
27
35
  totp.verify_with_drift(code, drift)
28
36
  else
@@ -38,7 +46,7 @@ module ActiveModel
38
46
  time = options
39
47
  padding = true
40
48
  end
41
- ROTP::TOTP.new(self.otp_column).at(time, padding)
49
+ ROTP::TOTP.new(self.otp_column, {digits: self.otp_digits}).at(time, padding)
42
50
  end
43
51
 
44
52
  def provisioning_uri(account = nil)
@@ -53,7 +61,6 @@ module ActiveModel
53
61
  def otp_column=(attr)
54
62
  self.send("#{self.class.otp_column_name}=", attr)
55
63
  end
56
-
57
64
  end
58
65
  end
59
66
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  module Otp
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
data/test/models/user.rb CHANGED
@@ -7,5 +7,4 @@ class User
7
7
  attr_accessor :otp_secret_key, :email
8
8
 
9
9
  has_one_time_password
10
-
11
10
  end
@@ -6,7 +6,6 @@ class Visitor
6
6
  define_model_callbacks :create
7
7
  attr_accessor :otp_token, :email
8
8
 
9
- has_one_time_password :column_name => :otp_token
10
-
9
+ has_one_time_password column_name: :otp_token, length: 4
11
10
  end
12
11
 
@@ -5,6 +5,7 @@ class OtpTest < MiniTest::Unit::TestCase
5
5
  @user = User.new
6
6
  @user.email = 'roberto@heapsource.com'
7
7
  @user.run_callbacks :create
8
+
8
9
  @visitor = Visitor.new
9
10
  @visitor.email = 'roberto@heapsource.com'
10
11
  @visitor.run_callbacks :create
@@ -12,6 +13,7 @@ class OtpTest < MiniTest::Unit::TestCase
12
13
 
13
14
  def test_authenticate_with_otp
14
15
  code = @user.otp_code
16
+
15
17
  assert @user.authenticate_otp(code)
16
18
 
17
19
  code = @visitor.otp_code
@@ -28,13 +30,25 @@ class OtpTest < MiniTest::Unit::TestCase
28
30
 
29
31
  def test_otp_code
30
32
  assert_match(/^\d{6}$/, @user.otp_code.to_s)
31
- assert_match(/^\d{6}$/, @visitor.otp_code.to_s)
33
+ assert_match(/^\d{4}$/, @visitor.otp_code.to_s)
34
+ end
35
+
36
+ def test_otp_code_with_specific_length
37
+ assert_match(/^\d{4}$/, @visitor.otp_code(time: 2160, padding: true).to_s)
38
+ assert_operator(@visitor.otp_code(time: 2160, padding: false).to_s.length, :<= , 4)
39
+ end
40
+
41
+ def test_otp_code_without_specific_length
42
+ assert_match(/^\d{6}$/, @user.otp_code(time: 2160, padding: true).to_s)
43
+ assert_operator(@user.otp_code(time: 2160, padding: false).to_s.length, :<= , 6)
32
44
  end
33
45
 
34
46
  def test_otp_code_padding
35
47
  @user.otp_column = 'kw5jhligwqaiw7jc'
36
48
  assert_match(/^\d{6}$/, @user.otp_code(time: 2160, padding: true).to_s)
37
- assert_match(/^\d{3}$/, @user.otp_code(time: 2160, padding: false).to_s)
49
+ # Modified this spec as it is not guranteed that without padding we will always
50
+ # get a 3 digit number
51
+ assert_operator(@user.otp_code(time: 2160, padding: false).to_s.length, :<= , 6)
38
52
  end
39
53
 
40
54
  def test_provisioning_uri_with_provided_account
@@ -46,4 +60,10 @@ class OtpTest < MiniTest::Unit::TestCase
46
60
  assert_match %r{otpauth://totp/roberto@heapsource\.com\?secret=\w{16}}, @user.provisioning_uri
47
61
  assert_match %r{otpauth://totp/roberto@heapsource\.com\?secret=\w{16}}, @visitor.provisioning_uri
48
62
  end
63
+
64
+ def test_regenerate_otp
65
+ secret = @user.otp_column
66
+ @user.otp_regenerate_secret
67
+ assert secret != @user.otp_column
68
+ end
49
69
  end
data/test/test_helper.rb CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
6
6
 
7
7
  require "rubygems"
8
8
  require "active_model_otp"
9
- require "minitest/unit"
10
9
  require "minitest/autorun"
10
+ require "minitest/unit"
11
11
 
12
12
  Dir["models/*.rb"].each {|file| require file }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Guillermo Iguaran
@@ -10,78 +10,78 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-08-01 00:00:00.000000000 Z
13
+ date: 2014-10-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - ! '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - ! '>='
26
+ - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  version: '0'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: rotp
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - ! '>='
33
+ - - ">="
34
34
  - !ruby/object:Gem::Version
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - ! '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: bundler
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ~>
47
+ - - "~>"
48
48
  - !ruby/object:Gem::Version
49
49
  version: '1.3'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ~>
54
+ - - "~>"
55
55
  - !ruby/object:Gem::Version
56
56
  version: '1.3'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: rake
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - ! '>='
61
+ - - ">="
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - ! '>='
68
+ - - ">="
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: minitest
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - ! '>='
75
+ - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: '0'
77
+ version: 5.4.2
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - ! '>='
82
+ - - "~>"
83
83
  - !ruby/object:Gem::Version
84
- version: '0'
84
+ version: 5.4.2
85
85
  description: Adds methods to set and authenticate against one time passwords. Inspired
86
86
  in AM::SecurePassword"
87
87
  email:
@@ -92,8 +92,8 @@ executables: []
92
92
  extensions: []
93
93
  extra_rdoc_files: []
94
94
  files:
95
- - .gitignore
96
- - .travis.yml
95
+ - ".gitignore"
96
+ - ".travis.yml"
97
97
  - CHANGELOG.md
98
98
  - Gemfile
99
99
  - LICENSE.txt
@@ -117,12 +117,12 @@ require_paths:
117
117
  - lib
118
118
  required_ruby_version: !ruby/object:Gem::Requirement
119
119
  requirements:
120
- - - ! '>='
120
+ - - ">="
121
121
  - !ruby/object:Gem::Version
122
122
  version: '0'
123
123
  required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  requirements:
125
- - - ! '>='
125
+ - - ">="
126
126
  - !ruby/object:Gem::Version
127
127
  version: '0'
128
128
  requirements: []