active_model_otp 1.0.0 → 1.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.
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: []