devise-2fa 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a7255cc70209ac3ac13a39250a8c2e815208fd0250faa4ad6ae5374ffbac6f9
4
- data.tar.gz: 2e3f41153f267a42156741a7bc6aa118055b71b809cdd0f991ff26840cfeef85
3
+ metadata.gz: a34165f30cdc2d197acd726713f2ca7a6ed4ac2d4410aea31c10d4c12958e45d
4
+ data.tar.gz: ce5559076cac73dedcb0454982e8cd0f6dcd6d79ef2113b8e2426cc626e2cf27
5
5
  SHA512:
6
- metadata.gz: 724f253be1752edb042bddc6e1747d072ec1f6a91e7bbd337d5ee409780cb9e65bcf88d4f185d1445ecc563f2f08c618530e458e3d9a0a7dbe7530e40cbd8639
7
- data.tar.gz: dd3dc80d4c369e0743a3bb16b602bbd7d6492601a5d81a8de274d60cc3b8bdfd25dbc7fa4699cae82c02e5419dca6cad11f05bcdb6acc6290287871d7e94347a
6
+ metadata.gz: 65d4138506168bbf1403791cb00573270781c30c54e9a7bf49b43c8145247188ac19fd7410558f86cc95c46986ecd5d78920725919210d0c24a2a2dbb36556b3
7
+ data.tar.gz: 8f2cc4f9f4f8215cc6b3e3cd0caf8e917608ac95ce3bbcfc6d371678fbaef8399f9cdccdc31cbe379319a244979278201c1607abc642c7c944a8f6275e6ed028
data/.circleci/config.yml CHANGED
@@ -1,45 +1,70 @@
1
1
  version: 2
2
+
3
+ build_config: &build_config
4
+ working_directory: ~/repo
5
+ steps:
6
+ - checkout
7
+
8
+ - restore_cache:
9
+ keys:
10
+ - v1-dependencies-{{ checksum "devise_2fa.gemspec" }}-{{ checksum "Appraisals" }}
11
+ - v1-dependencies-{{ checksum "devise_2fa.gemspec" }}
12
+ - v1-dependencies
13
+
14
+ - run: bin/setup
15
+
16
+ - save_cache:
17
+ paths:
18
+ - ./vendor/bundle
19
+ key: v1-dependencies-{{ checksum "devise_2fa.gemspec" }}-{{ checksum "Appraisals" }}
20
+
21
+ - run:
22
+ name: Setup Symmetric Encryption Config
23
+ command: |
24
+ cd spec/dummy/
25
+ symmetric-encryption -g
26
+
27
+ - run:
28
+ name: Run Tests
29
+ command: |
30
+ mkdir /tmp/test-results
31
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
32
+ circleci tests split --split-by=timings)"
33
+
34
+ bundle exec appraisal rspec \
35
+ --format progress \
36
+ --format RspecJunitFormatter \
37
+ --out /tmp/test-results/rspec.xml \
38
+ --format progress \
39
+ $TEST_FILES
40
+
41
+ - store_test_results:
42
+ path: /tmp/test-results
43
+ - store_artifacts:
44
+ path: /tmp/test-results
45
+ destination: test-results
46
+
2
47
  jobs:
48
+ ruby-2.4:
49
+ <<: *build_config
50
+ docker:
51
+ - image: circleci/ruby:2.4-node-browsers
52
+ - image: circleci/mongo
53
+ ruby-2.5:
54
+ <<: *build_config
55
+ docker:
56
+ - image: circleci/ruby:2.5-node-browsers
57
+ - image: circleci/mongo
3
58
  build:
59
+ <<: *build_config
4
60
  docker:
5
- - image: circleci/ruby:2.4.1-node-browsers
6
-
7
- working_directory: ~/repo
8
-
9
- steps:
10
- - checkout
11
-
12
- - restore_cache:
13
- keys:
14
- - v1-dependencies-{{ checksum "devise_2fa.gemspec" }}
15
-
16
- - run:
17
- name: install dependencies
18
- command: |
19
- bundle install --jobs=4 --retry=3 --path vendor/bundle
20
-
21
- - save_cache:
22
- paths:
23
- - ./vendor/bundle
24
- key: v1-dependencies-{{ checksum "devise_2fa.gemspec" }}
25
-
26
- - run: cd spec/dummy && bin/setup
27
-
28
- - run:
29
- name: run tests
30
- command: |
31
- mkdir /tmp/test-results
32
- TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
33
- circleci tests split --split-by=timings)"
34
-
35
- bundle exec rspec \
36
- --format progress \
37
- --out /tmp/test-results/rspec.xml \
38
- --format progress \
39
- $TEST_FILES
40
-
41
- - store_test_results:
42
- path: /tmp/test-results
43
- - store_artifacts:
44
- path: /tmp/test-results
45
- destination: test-results
61
+ - image: circleci/ruby:2.6-node-browsers
62
+ - image: circleci/mongo
63
+
64
+ workflows:
65
+ version: 2
66
+ build:
67
+ jobs:
68
+ - ruby-2.4
69
+ - ruby-2.5
70
+ - build
data/.gitignore CHANGED
@@ -42,3 +42,6 @@ spec/dummy/db/test.sqlite3
42
42
  *.cache
43
43
  spec/dummy/tmp/development_secret.txt
44
44
  spec/dummy/tmp/restart.txt
45
+
46
+ gemfiles/
47
+ Gemfile.lock
data/Appraisals ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise 'sqlite3' do
4
+ gem 'rails', '~> 5.2'
5
+ gem 'sqlite3'
6
+ end
7
+
8
+ appraise 'mongodb' do
9
+ gem 'rails', '~> 5.2'
10
+ gem 'mongoid'
11
+ gem 'bson_ext'
12
+ end
data/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.0] - 2019-08-22
10
+ ### Added
11
+ - Appraisal suite.
12
+ - Mongoid specs.
13
+
14
+ ### Changed
15
+ - Refactors #validate_otp_token_with_drift from #15.
16
+ - Upgraded rotp dependency to ```~> 5.1```.
17
+
18
+ ## [0.3.0] - REVOKED
19
+
9
20
  ## [0.2.1] - 2019-05-28
10
21
  ### Changed
11
22
  - Relaxed Rails dependency to ```~> 6.1```.
data/bin/rspec CHANGED
@@ -1,10 +1,3 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
1
+ #!/bin/bash
3
2
 
4
- begin
5
- load File.expand_path('../spring', __FILE__)
6
- rescue LoadError => e
7
- raise unless e.message.include?('spring')
8
- end
9
- require 'bundler/setup'
10
- load Gem.bin_path('rspec-core', 'rspec')
3
+ bundle exec appraisal rspec
data/bin/setup CHANGED
@@ -9,4 +9,6 @@ echo "Installing dependencies"
9
9
  gem install bundler --conservative
10
10
  bundle check || bundle install
11
11
 
12
- $DIR/../spec/dummy/bin/setup
12
+ bundle exec appraisal install
13
+
14
+ bundle exec appraisal $DIR/../spec/dummy/bin/setup
data/devise_2fa.gemspec CHANGED
@@ -21,14 +21,15 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency "rails", ">= 4.1", "< 6.1"
22
22
 
23
23
  gem.add_runtime_dependency 'devise', '~> 4.0'
24
- gem.add_runtime_dependency 'rotp', '~> 4.1'
24
+ gem.add_runtime_dependency 'rotp', '~> 5.1'
25
25
  gem.add_runtime_dependency 'rqrcode', '~> 0.10.1'
26
26
  gem.add_runtime_dependency 'symmetric-encryption', '~> 4.3.0'
27
27
 
28
- gem.add_development_dependency 'sqlite3', '~> 1.3.6'
29
- gem.add_development_dependency 'selenium-webdriver'
30
- gem.add_development_dependency 'rspec-rails'
28
+ gem.add_development_dependency 'appraisal'
31
29
  gem.add_development_dependency 'capybara'
32
- gem.add_development_dependency 'rspec'
33
30
  gem.add_development_dependency 'pry'
31
+ gem.add_development_dependency 'rspec'
32
+ gem.add_development_dependency 'rspec-rails'
33
+ gem.add_development_dependency 'rspec_junit_formatter'
34
+ gem.add_development_dependency 'selenium-webdriver'
34
35
  end
@@ -1,5 +1,5 @@
1
1
  module Devise
2
2
  module TwoFactor
3
- VERSION = '0.2.1'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
  end
5
5
  end
@@ -117,10 +117,15 @@ module Devise::Models
117
117
  private
118
118
 
119
119
  def validate_otp_token_with_drift(token)
120
- # should be centered around saved drift
121
- (-self.class.otp_drift_window..self.class.otp_drift_window).any? do |drift|
122
- time_based_otp.verify(token, drift_behind: (0.5 * drift), at: Time.now + (0.5 * drift))
123
- end
120
+ time_based_otp.verify(
121
+ token,
122
+ drift_behind: drift.minutes.seconds,
123
+ at: Time.now + drift.minutes.seconds / 2
124
+ )
125
+ end
126
+
127
+ def drift
128
+ self.class.otp_drift_window
124
129
  end
125
130
 
126
131
  def generate_otp_persistence_seed
@@ -1,3 +1,7 @@
1
- class ApplicationRecord < ActiveRecord::Base
2
- self.abstract_class = true
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(ActiveRecord)
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ end
3
7
  end
@@ -1,6 +1,38 @@
1
- class User < ApplicationRecord
2
- # Include default devise modules. Others available are:
3
- # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
4
- devise :two_factorable, :database_authenticatable, :registerable,
5
- :recoverable, :rememberable, :validatable
1
+ # frozen_string_literal: true
2
+
3
+ require 'symmetric_encryption'
4
+
5
+ if defined?(ActiveRecord)
6
+ class User < ApplicationRecord
7
+ devise :two_factorable, :database_authenticatable, :registerable,
8
+ :recoverable, :rememberable, :validatable
9
+ end
10
+ else
11
+ require 'mongoid'
12
+ class User
13
+ include Mongoid::Document
14
+ field :encrypted_otp_auth_secret, type: String, encrypted: true
15
+ field :encrypted_otp_recovery_secret, type: String, encrypted: true
16
+ field :otp_enabled, type: Boolean, default: false
17
+ field :otp_mandatory, type: Boolean, default: false
18
+ field :otp_enabled_on, type: DateTime
19
+ field :otp_failed_attempts, type: Integer, default: 0
20
+ field :otp_recovery_counter, type: Integer, default: 0
21
+ field :otp_persistence_seed, type: String
22
+ field :otp_session_challenge, type: String
23
+ field :otp_challenge_expires, type: DateTime
24
+
25
+ index({ otp_session_challenge: 1 }, background: true)
26
+ index({ otp_challenge_expires: 1 }, background: true)
27
+
28
+ devise :two_factorable, :database_authenticatable, :registerable,
29
+ :recoverable, :rememberable, :validatable
30
+ field :email, type: String, default: ''
31
+ field :encrypted_password, type: String, default: ''
32
+ field :reset_password_token, type: String
33
+ field :reset_password_sent_at, type: Time
34
+ field :remember_created_at, type: Time
35
+ field :name, type: String
36
+ field :phone, type: String
37
+ end
6
38
  end
@@ -7,9 +7,6 @@
7
7
  <title>Dummy</title>
8
8
  <%= csrf_meta_tags %>
9
9
  <%= csp_meta_tag %>
10
-
11
- <%= stylesheet_link_tag 'application', media: 'all' %>
12
- <%= javascript_include_tag 'application' %>
13
10
  </head>
14
11
 
15
12
  <body>
data/spec/dummy/bin/setup CHANGED
@@ -5,21 +5,6 @@ include FileUtils
5
5
  # path to your application root.
6
6
  APP_ROOT = File.expand_path('..', __dir__)
7
7
 
8
- def system!(*args)
9
- system(*args) || abort("\n== Command #{args} failed ==")
10
- end
11
-
12
8
  chdir APP_ROOT do
13
- puts '== Installing dependencies =='
14
- system! 'gem install bundler --conservative'
15
- system('bundle check') || system!('bundle install')
16
-
17
- puts "\n== Preparing database =="
18
- system! 'bin/rails db:setup'
19
-
20
- puts "\n== Removing old logs and tempfiles =="
21
- system! 'bin/rails log:clear tmp:clear'
22
-
23
- puts "\n== Restarting application server =="
24
- system! 'bin/rails restart'
9
+ system 'bin/rails db:setup 2> /dev/null'
25
10
  end
@@ -1,6 +1,14 @@
1
1
  require_relative 'boot'
2
2
 
3
- require 'rails/all'
3
+ require 'rails'
4
+ require 'active_model/railtie'
5
+ unless ENV['BUNDLE_GEMFILE'].include?('mongodb')
6
+ require 'active_record/railtie'
7
+ end
8
+ require 'action_controller/railtie'
9
+ require 'action_view/railtie'
10
+ require 'sprockets/railtie'
11
+ require 'rails/test_unit/railtie'
4
12
 
5
13
  Bundler.require(*Rails.groups)
6
14
  require 'devise-2fa'
@@ -11,4 +19,3 @@ module Dummy
11
19
  config.load_defaults 5.0
12
20
  end
13
21
  end
14
-
@@ -1,9 +1,3 @@
1
- # SQLite version 3.x
2
- # gem install sqlite3
3
- #
4
- # Ensure the SQLite 3 gem is defined in your Gemfile
5
- # gem 'sqlite3'
6
- #
7
1
  default: &default
8
2
  adapter: sqlite3
9
3
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
@@ -19,7 +13,3 @@ development:
19
13
  test:
20
14
  <<: *default
21
15
  database: db/test.sqlite3
22
-
23
- production:
24
- <<: *default
25
- database: db/production.sqlite3
@@ -27,23 +27,9 @@ Rails.application.configure do
27
27
  config.cache_store = :null_store
28
28
  end
29
29
 
30
- # Store uploaded files on the local file system (see config/storage.yml for options)
31
- config.active_storage.service = :local
32
-
33
- # Don't care if the mailer can't send.
34
- config.action_mailer.raise_delivery_errors = false
35
-
36
- config.action_mailer.perform_caching = false
37
-
38
30
  # Print deprecation notices to the Rails logger.
39
31
  config.active_support.deprecation = :log
40
32
 
41
- # Raise an error on page load if there are pending migrations.
42
- config.active_record.migration_error = :page_load
43
-
44
- # Highlight code that triggered database queries in logs.
45
- config.active_record.verbose_query_logs = true
46
-
47
33
  # Debug mode disables concatenation and preprocessing of assets.
48
34
  # This option may cause significant delays in view rendering with a large
49
35
  # number of complex assets.
@@ -10,7 +10,7 @@ Rails.application.configure do
10
10
  # Do not eager load code on boot. This avoids loading your whole application
11
11
  # just for the purpose of running a single test. If you are using a tool that
12
12
  # preloads Rails for running tests, you may have to set it to true.
13
- config.eager_load = false
13
+ config.eager_load = true
14
14
 
15
15
  # Configure public file server for tests with Cache-Control for performance
16
16
  config.public_file_server.enabled = true
@@ -28,19 +28,6 @@ Rails.application.configure do
28
28
  # Disable request forgery protection in test environment
29
29
  config.action_controller.allow_forgery_protection = false
30
30
 
31
- # Store uploaded files on the local file system in a temporary directory
32
- config.active_storage.service = :test
33
-
34
- config.action_mailer.perform_caching = false
35
-
36
- # Tell Action Mailer not to deliver emails to the real world
37
- # The :test delivery method accumulates sent emails in the
38
- # ActionMailer::Base.deliveries array.
39
- config.action_mailer.delivery_method = :test
40
-
41
31
  # Print deprecation notices to the stderr
42
32
  config.active_support.deprecation = :stderr
43
-
44
- # Raises error for missing translations
45
- # config.action_view.raise_on_missing_translations = true
46
33
  end
@@ -30,7 +30,11 @@ Devise.setup do |config|
30
30
  # Load and configure the ORM. Supports :active_record (default) and
31
31
  # :mongoid (bson_ext recommended) by default. Other ORMs may be
32
32
  # available as additional gems.
33
- require 'devise/orm/active_record'
33
+ if defined?(ActiveRecord)
34
+ require 'devise/orm/active_record'
35
+ else
36
+ require 'devise/orm/mongoid'
37
+ end
34
38
 
35
39
  # ==> Configuration for any authentication mechanism
36
40
  # Configure which keys are used when authenticating a user. The default is
@@ -0,0 +1,164 @@
1
+ development:
2
+ # Configure available database clients. (required)
3
+ clients:
4
+ # Defines the default client. (required)
5
+ default:
6
+ # Defines the name of the default database that Mongoid can connect to.
7
+ # (required).
8
+ database: dummy_development
9
+ # Provides the hosts the default client can connect to. Must be an array
10
+ # of host:port pairs. (required)
11
+ hosts:
12
+ - localhost:27017
13
+ options:
14
+ # Note that all options listed below are Ruby driver client options (the mongo gem).
15
+ # Please refer to the driver documentation of the version of the mongo gem you are using
16
+ # for the most up-to-date list of options.
17
+ #
18
+ # Change the default write concern. (default = { w: 1 })
19
+ # write:
20
+ # w: 1
21
+
22
+ # Change the default read preference. Valid options for mode are: :secondary,
23
+ # :secondary_preferred, :primary, :primary_preferred, :nearest
24
+ # (default: primary)
25
+ # read:
26
+ # mode: :secondary_preferred
27
+ # tag_sets:
28
+ # - use: web
29
+
30
+ # The name of the user for authentication.
31
+ # user: 'user'
32
+
33
+ # The password of the user for authentication.
34
+ # password: 'password'
35
+
36
+ # The user's database roles.
37
+ # roles:
38
+ # - 'dbOwner'
39
+
40
+ # Change the default authentication mechanism. Valid options are: :scram,
41
+ # :mongodb_cr, :mongodb_x509, and :plain. Note that all authentication
42
+ # mechanisms require username and password, with the exception of :mongodb_x509.
43
+ # Default on mongoDB 3.0 is :scram, default on 2.4 and 2.6 is :plain.
44
+ # auth_mech: :scram
45
+
46
+ # The database or source to authenticate the user against.
47
+ # (default: the database specified above or admin)
48
+ # auth_source: admin
49
+
50
+ # Force a the driver cluster to behave in a certain manner instead of auto-
51
+ # discovering. Can be one of: :direct, :replica_set, :sharded. Set to :direct
52
+ # when connecting to hidden members of a replica set.
53
+ # connect: :direct
54
+
55
+ # Changes the default time in seconds the server monitors refresh their status
56
+ # via ismaster commands. (default: 10)
57
+ # heartbeat_frequency: 10
58
+
59
+ # The time in seconds for selecting servers for a near read preference. (default: 0.015)
60
+ # local_threshold: 0.015
61
+
62
+ # The timeout in seconds for selecting a server for an operation. (default: 30)
63
+ # server_selection_timeout: 30
64
+
65
+ # The maximum number of connections in the connection pool. (default: 5)
66
+ # max_pool_size: 5
67
+
68
+ # The minimum number of connections in the connection pool. (default: 1)
69
+ # min_pool_size: 1
70
+
71
+ # The time to wait, in seconds, in the connection pool for a connection
72
+ # to be checked in before timing out. (default: 5)
73
+ # wait_queue_timeout: 5
74
+
75
+ # The time to wait to establish a connection before timing out, in seconds.
76
+ # (default: 5)
77
+ # connect_timeout: 5
78
+
79
+ # The timeout to wait to execute operations on a socket before raising an error.
80
+ # (default: 5)
81
+ # socket_timeout: 5
82
+
83
+ # The name of the replica set to connect to. Servers provided as seeds that do
84
+ # not belong to this replica set will be ignored.
85
+ # replica_set: name
86
+
87
+ # Whether to connect to the servers via ssl. (default: false)
88
+ # ssl: true
89
+
90
+ # The certificate file used to identify the connection against MongoDB.
91
+ # ssl_cert: /path/to/my.cert
92
+
93
+ # The private keyfile used to identify the connection against MongoDB.
94
+ # Note that even if the key is stored in the same file as the certificate,
95
+ # both need to be explicitly specified.
96
+ # ssl_key: /path/to/my.key
97
+
98
+ # A passphrase for the private key.
99
+ # ssl_key_pass_phrase: password
100
+
101
+ # Whether or not to do peer certification validation. (default: true)
102
+ # ssl_verify: true
103
+
104
+ # The file containing a set of concatenated certification authority certifications
105
+ # used to validate certs passed from the other end of the connection.
106
+ # ssl_ca_cert: /path/to/ca.cert
107
+
108
+
109
+ # Configure Mongoid specific options. (optional)
110
+ options:
111
+ # Includes the root model name in json serialization. (default: false)
112
+ # include_root_in_json: false
113
+
114
+ # Include the _type field in serialization. (default: false)
115
+ # include_type_for_serialization: false
116
+
117
+ # Preload all models in development, needed when models use
118
+ # inheritance. (default: false)
119
+ # preload_models: false
120
+
121
+ # Raise an error when performing a #find and the document is not found.
122
+ # (default: true)
123
+ # raise_not_found_error: true
124
+
125
+ # Raise an error when defining a scope with the same name as an
126
+ # existing method. (default: false)
127
+ # scope_overwrite_exception: false
128
+
129
+ # Raise an error when defining a field with the same name as an
130
+ # existing method. (default: false)
131
+ # duplicate_fields_exception: false
132
+
133
+ # Use Active Support's time zone in conversions. (default: true)
134
+ # use_activesupport_time_zone: true
135
+
136
+ # Ensure all times are UTC in the app side. (default: false)
137
+ # use_utc: false
138
+
139
+ # Set the Mongoid and Ruby driver log levels when not in a Rails
140
+ # environment. The Mongoid logger will be set to the Rails logger
141
+ # otherwise.(default: :info)
142
+ # log_level: :info
143
+
144
+ # Control whether `belongs_to` association is required. By default
145
+ # `belongs_to` will trigger a validation error if the association
146
+ # is not present. (default: true)
147
+ # belongs_to_required_by_default: true
148
+
149
+ # Application name that is printed to the mongodb logs upon establishing a
150
+ # connection in server versions >= 3.4. Note that the name cannot exceed 128 bytes.
151
+ # app_name: MyApplicationName
152
+
153
+ # Use background indexes by default if `background` option not specified. (default: false)
154
+ # background_indexing: false
155
+ test:
156
+ clients:
157
+ default:
158
+ database: dummy_test
159
+ hosts:
160
+ - localhost:27017
161
+ options:
162
+ read:
163
+ mode: :primary
164
+ max_pool_size: 1
@@ -1,4 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative Rails.root.join('app/models/user')
4
+
5
+
1
6
  Rails.application.routes.draw do
2
7
  devise_for :users
3
- root to: "application#show"
8
+ root to: 'application#show'
4
9
  end
@@ -1,4 +1,4 @@
1
- class DeviseTwoFactorAddToUsers < ActiveRecord::Migration[5.0]
1
+ class DeviseTwoFactorAddToUsers < ActiveRecord::Migration
2
2
  def self.up
3
3
  change_table :users do |t|
4
4
  t.string :otp_auth_secret
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe User, type: :model do
6
- subject (:user) { User.new(email: 'mb@geemail.com', password: 'iwantabigmac1') }
6
+ subject(:user) { User.create(email: 'mb@geemail.com', password: 'iwantabigmac1') }
7
7
  it 'is valid' do
8
8
  expect(user).to be_valid
9
9
  end
@@ -23,11 +23,56 @@ RSpec.describe User, type: :model do
23
23
  end
24
24
 
25
25
  describe '#password' do
26
- subject(:user) { User.new(email: 'mb@geemail.com')}
26
+ subject(:user) { User.new(email: 'mb@geemail.com') }
27
27
 
28
28
  it 'is required' do
29
29
  expect(user).to be_invalid
30
30
  end
31
31
  end
32
32
  end
33
+
34
+ describe '#validate_otp_token' do
35
+ context 'when otp_drift_window is 3 minutes (default)' do
36
+ let(:user_rotp) { ROTP::TOTP.new(user.otp_auth_secret) }
37
+ let(:control_time) { Time.now }
38
+ let(:token_time) { control_time }
39
+
40
+ before do
41
+ Devise.otp_drift_window = 3
42
+ allow(Time).to receive(:now).and_return(control_time)
43
+ end
44
+
45
+ context "when token's time is 2 minutes before current time" do
46
+ let(:token_time) { control_time - 2.minutes }
47
+
48
+ it do
49
+ expect(user.validate_otp_token(user_rotp.at(token_time))).to be_falsey
50
+ end
51
+ end
52
+
53
+ context "when token's time is 1 minute before current time" do
54
+ let(:token_time) { control_time - 1.minute }
55
+
56
+ it do
57
+ expect(user.validate_otp_token(user_rotp.at(token_time))).to be_truthy
58
+ end
59
+ end
60
+
61
+ context "when token's time is 1 minute after current time" do
62
+ let(:token_time) { control_time + 1.minute }
63
+
64
+ it do
65
+ expect(user.validate_otp_token(user_rotp.at(token_time))).to be_truthy
66
+ end
67
+ end
68
+
69
+ context "when token's time is 2 minutes after current time" do
70
+ let(:token_time) { control_time + 2.minute }
71
+
72
+ it do
73
+ expect(user.validate_otp_token(user_rotp.at(token_time))).to be_falsey
74
+ end
75
+ end
76
+ end
77
+ end
33
78
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- ENV["RAILS_ENV"] ||= "test"
3
+ ENV['RAILS_ENV'] ||= 'test'
4
4
 
5
- require "rails/all"
6
- require "dummy/config/application"
5
+ require 'dummy/config/application'
7
6
  require 'bundler/setup'
8
7
  require 'rspec/rails'
9
8
 
@@ -24,6 +23,11 @@ RSpec.configure do |config|
24
23
  config.before(:each, type: :system) do
25
24
  driven_by :rack_test
26
25
  end
26
+ if defined? Mongoid
27
+ config.before :each do
28
+ Mongoid.purge!
29
+ end
30
+ end
27
31
  end
28
32
 
29
33
 
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  RSpec.describe 'Tokens' do
6
- subject (:user) { User.create(email: 'mb@geemail.com', password: 'iwantabigmac1') }
6
+ subject(:user) { User.create(email: 'mb@geemail.com', password: 'iwantabigmac1') }
7
7
 
8
8
  it 'can be disabled by a user after successfully enabling' do
9
9
  enable_otp_and_sign_in user
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-2fa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - William A. Todd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-28 00:00:00.000000000 Z
11
+ date: 2019-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -50,14 +50,14 @@ dependencies:
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '4.1'
53
+ version: '5.1'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '4.1'
60
+ version: '5.1'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rqrcode
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -87,21 +87,21 @@ dependencies:
87
87
  - !ruby/object:Gem::Version
88
88
  version: 4.3.0
89
89
  - !ruby/object:Gem::Dependency
90
- name: sqlite3
90
+ name: appraisal
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: 1.3.6
95
+ version: '0'
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - "~>"
100
+ - - ">="
101
101
  - !ruby/object:Gem::Version
102
- version: 1.3.6
102
+ version: '0'
103
103
  - !ruby/object:Gem::Dependency
104
- name: selenium-webdriver
104
+ name: capybara
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - ">="
@@ -115,7 +115,7 @@ dependencies:
115
115
  - !ruby/object:Gem::Version
116
116
  version: '0'
117
117
  - !ruby/object:Gem::Dependency
118
- name: rspec-rails
118
+ name: pry
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - ">="
@@ -129,7 +129,7 @@ dependencies:
129
129
  - !ruby/object:Gem::Version
130
130
  version: '0'
131
131
  - !ruby/object:Gem::Dependency
132
- name: capybara
132
+ name: rspec
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - ">="
@@ -143,7 +143,7 @@ dependencies:
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  - !ruby/object:Gem::Dependency
146
- name: rspec
146
+ name: rspec-rails
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - ">="
@@ -157,7 +157,21 @@ dependencies:
157
157
  - !ruby/object:Gem::Version
158
158
  version: '0'
159
159
  - !ruby/object:Gem::Dependency
160
- name: pry
160
+ name: rspec_junit_formatter
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: selenium-webdriver
161
175
  requirement: !ruby/object:Gem::Requirement
162
176
  requirements:
163
177
  - - ">="
@@ -181,6 +195,7 @@ files:
181
195
  - ".gitignore"
182
196
  - ".hound.yml"
183
197
  - ".ruby-style.yml"
198
+ - Appraisals
184
199
  - CHANGELOG.md
185
200
  - Gemfile
186
201
  - LICENSE
@@ -217,10 +232,6 @@ files:
217
232
  - lib/generators/devise_two_factor/views_generator.rb
218
233
  - lib/generators/mongoid/devise_two_factor_generator.rb
219
234
  - spec/dummy/Rakefile
220
- - spec/dummy/app/assets/images/.keep
221
- - spec/dummy/app/assets/javascripts/application.js
222
- - spec/dummy/app/assets/javascripts/channels/.keep
223
- - spec/dummy/app/assets/stylesheets/application.css
224
235
  - spec/dummy/app/controllers/application_controller.rb
225
236
  - spec/dummy/app/controllers/concerns/.keep
226
237
  - spec/dummy/app/helpers/application_helper.rb
@@ -253,12 +264,13 @@ files:
253
264
  - spec/dummy/config/locales/devise.en.yml
254
265
  - spec/dummy/config/locales/devise.two_factor.en.yml
255
266
  - spec/dummy/config/locales/en.yml
267
+ - spec/dummy/config/mongoid.yml
256
268
  - spec/dummy/config/puma.rb
257
269
  - spec/dummy/config/routes.rb
258
270
  - spec/dummy/config/spring.rb
259
271
  - spec/dummy/config/storage.yml
260
272
  - spec/dummy/db/migrate/20190311184605_devise_create_users.rb
261
- - spec/dummy/db/migrate/20190312222952_devise_two_factor_add_to_users.rb
273
+ - spec/dummy/db/migrate/20190625052821_devise_two_factor_add_to_users.rb
262
274
  - spec/dummy/db/schema.rb
263
275
  - spec/dummy/lib/assets/.keep
264
276
  - spec/dummy/package.json
@@ -294,16 +306,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
294
306
  - !ruby/object:Gem::Version
295
307
  version: '0'
296
308
  requirements: []
297
- rubygems_version: 3.0.2
309
+ rubygems_version: 3.0.4
298
310
  signing_key:
299
311
  specification_version: 4
300
312
  summary: Includes ActiveRecord and Mongoid ORM support
301
313
  test_files:
302
314
  - spec/dummy/Rakefile
303
- - spec/dummy/app/assets/images/.keep
304
- - spec/dummy/app/assets/javascripts/application.js
305
- - spec/dummy/app/assets/javascripts/channels/.keep
306
- - spec/dummy/app/assets/stylesheets/application.css
307
315
  - spec/dummy/app/controllers/application_controller.rb
308
316
  - spec/dummy/app/controllers/concerns/.keep
309
317
  - spec/dummy/app/helpers/application_helper.rb
@@ -336,12 +344,13 @@ test_files:
336
344
  - spec/dummy/config/locales/devise.en.yml
337
345
  - spec/dummy/config/locales/devise.two_factor.en.yml
338
346
  - spec/dummy/config/locales/en.yml
347
+ - spec/dummy/config/mongoid.yml
339
348
  - spec/dummy/config/puma.rb
340
349
  - spec/dummy/config/routes.rb
341
350
  - spec/dummy/config/spring.rb
342
351
  - spec/dummy/config/storage.yml
343
352
  - spec/dummy/db/migrate/20190311184605_devise_create_users.rb
344
- - spec/dummy/db/migrate/20190312222952_devise_two_factor_add_to_users.rb
353
+ - spec/dummy/db/migrate/20190625052821_devise_two_factor_add_to_users.rb
345
354
  - spec/dummy/db/schema.rb
346
355
  - spec/dummy/lib/assets/.keep
347
356
  - spec/dummy/package.json
File without changes
@@ -1,3 +0,0 @@
1
- //= require rails-ujs
2
- //= require activestorage
3
- //= require_tree .
File without changes
@@ -1,15 +0,0 @@
1
- /*
2
- * This is a manifest file that'll be compiled into application.css, which will include all the files
3
- * listed below.
4
- *
5
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
- * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
- *
8
- * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
- * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
- * files in this directory. Styles in this file should be added after the last require_* statement.
11
- * It is generally better to create a new file per style scope.
12
- *
13
- *= require_tree .
14
- *= require_self
15
- */