Compare commits

..

No commits in common. 'master' and 'get_specs_running' have entirely different histories.

  1. 21
      .codeclimate.yml
  2. 42
      .github/workflows/tests.yml
  3. 28
      .travis.yml
  4. 1
      Gemfile
  5. 27
      README.md
  6. 4
      app/controllers/devise/two_factor_authentication_controller.rb
  7. 14
      lib/devise_two_factor_authentication/orm/active_record.rb
  8. 7
      lib/devise_two_factor_authentication/rails.rb
  9. 3
      lib/devise_two_factor_authentication/version.rb
  10. 18
      lib/two_factor_authentication.rb
  11. 6
      lib/two_factor_authentication/controllers/helpers.rb
  12. 6
      lib/two_factor_authentication/hooks/two_factor_authenticatable.rb
  13. 4
      lib/two_factor_authentication/models/two_factor_authenticatable.rb
  14. 14
      lib/two_factor_authentication/orm/active_record.rb
  15. 7
      lib/two_factor_authentication/rails.rb
  16. 10
      lib/two_factor_authentication/routes.rb
  17. 2
      lib/two_factor_authentication/schema.rb
  18. 3
      lib/two_factor_authentication/version.rb
  19. 5
      spec/rails_app/config/application.rb
  20. 37
      spec/rails_app/db/schema.rb
  21. 2
      spec/support/controller_helper.rb
  22. 4
      spec/support/features_spec_helper.rb
  23. 16
      two_factor_authentication.gemspec

21
.codeclimate.yml

@ -0,0 +1,21 @@
engines:
brakeman:
enabled: true
duplication:
enabled: true
config:
languages:
- ruby
# mass_threshold: 30
exclude_paths:
- 'spec/**/*'
fixme:
enabled: true
rubocop:
enabled: true
ratings:
paths:
- app/**
- lib/**
- '**.rb'

42
.github/workflows/tests.yml

@ -1,42 +0,0 @@
name: 'CI/CD Pipeline'
on:
push:
branches:
- master
pull_request:
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
test:
name: Test
runs-on: ubuntu-latest
env:
RAILS_ENV: test
GEMFILE_RUBY_VERSION: 3.0.3
# Rails verifies the time zone in DB is the same as the time zone of the Rails app
TZ: "Europe/London"
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.0.3
# runs 'bundle install' and caches installed gems automatically
bundler-cache: true
- name: Run tests
run: |
bundle exec rake spec

28
.travis.yml

@ -0,0 +1,28 @@
language: ruby
env:
- "RAILS_VERSION=4.2"
- "RAILS_VERSION=5.2"
- "RAILS_VERSION=master"
rvm:
- 2.3.8
- 2.4.5
- 2.5.3
matrix:
fast_finish: true
allow_failures:
- env: "RAILS_VERSION=master"
include:
- rvm: 2.2
env: RAILS_VERSION=4.2
before_install:
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
- gem install bundler -v '< 2'
before_script:
- bundle exec rake app:db:setup
script: bundle exec rake spec

1
Gemfile

@ -24,7 +24,6 @@ end
group :test, :development do
gem 'pry'
gem 'rubocop'
gem 'sprockets-rails'
gem 'sqlite3'
end

27
README.md

@ -1,9 +1,9 @@
# Two factor authentication for Devise
[![Build Status](https://github.com/devise2fa/two_factor_authentication/actions/workflows/tests.yml/badge.svg?branch=master&event=push)](https://github.com/baarkerlounger/two_factor_authentication/actions/workflows/tests.yml)
This is a fork of [Houdini/two_factor_authentication](https://github.com/Houdini/two_factor_authentication) to enable development to continue as that repository no longer seems to be actively developed. With thanks to all contributors.
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Houdini/two_factor_authentication?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/Houdini/two_factor_authentication.svg?branch=master)](https://travis-ci.org/Houdini/two_factor_authentication)
[![Code Climate](https://codeclimate.com/github/Houdini/two_factor_authentication.svg)](https://codeclimate.com/github/Houdini/two_factor_authentication)
## Features
@ -271,9 +271,9 @@ to overwrite/customize user registrations. It should include the lines below, fo
```ruby
class RegistrationsController < Devise::RegistrationsController
before_action :confirm_two_factor_authenticated, except: [:new, :create, :cancel]
protected
def confirm_two_factor_authenticated
return if is_fully_authenticated?
@ -296,7 +296,7 @@ Make sure you are passing the 2FA secret codes securely and checking for them up
before_action :require_signed_in!
before_action :authenticate_user!
respond_to :html, :json
def account_API
resp = {}
begin
@ -315,11 +315,11 @@ Make sure you are passing the 2FA secret codes securely and checking for them up
if(account_params["twoFASecret"] && current_user.totp_enabled? && current_user.authenticate_totp(account_params["twoFASecret"]))
# user has passed 2FA checks, do cool user account stuff here
...
else
else
# user failed 2FA check! No cool user stuff happens!
resp[error] = 'You failed 2FA validation!'
end
...
end
else
@ -332,7 +332,7 @@ Make sure you are passing the 2FA secret codes securely and checking for them up
end
render json: resp.to_json
end
def account_params
params.require(:twoFA).permit(:userAccountStuff, :userAcountWidget, :twoFAKey, :twoFASecret)
end
@ -357,7 +357,7 @@ to set up TOTP for Google Authenticator for user:
current_user.otp_secret_key = current_user.generate_totp_secret
current_user.save!
```
( encrypted db fields are set upon user model save action,
rails c access relies on setting env var: OTP_SECRET_ENCRYPTION_KEY )
@ -369,11 +369,11 @@ before saving the user model:
```
additional note:
```
current_user.otp_secret_key
```
This returns the OTP secret key in plaintext for the user (if you have set the env var) in the console
the string used for generating the QR given to the user for their Google Auth is something like:
@ -399,3 +399,6 @@ to set TOTP to DISABLED for a user account:
current_user.direct_otp? => false
current_user.totp_enabled? => false
```

4
app/controllers/devise/two_factor_authentication_controller.rb

@ -27,7 +27,7 @@ class Devise::TwoFactorAuthenticationController < DeviseController
def after_two_factor_success_for(resource)
set_remember_two_factor_cookie(resource)
warden.session(resource_name)[DeviseTwoFactorAuthentication::NEED_AUTHENTICATION] = false
warden.session(resource_name)[TwoFactorAuthentication::NEED_AUTHENTICATION] = false
# For compatability with devise versions below v4.2.0
# https://github.com/plataformatec/devise/commit/2044fffa25d781fcbaf090e7728b48b65c854ccb
if respond_to?(:bypass_sign_in)
@ -45,7 +45,7 @@ class Devise::TwoFactorAuthenticationController < DeviseController
expires_seconds = resource.class.remember_otp_session_for_seconds
if expires_seconds && expires_seconds > 0
cookies.signed[DeviseTwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] = {
cookies.signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] = {
value: "#{resource.class}-#{resource.public_send(Devise.second_factor_resource_id)}",
expires: expires_seconds.seconds.from_now
}

14
lib/devise_two_factor_authentication/orm/active_record.rb

@ -1,14 +0,0 @@
require "active_record"
module Devise2Fa
module Orm
module ActiveRecord
module Schema
# include Devise2Fa::Schema
end
end
end
end
ActiveRecord::ConnectionAdapters::Table.send :include, Devise2Fa::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, Devise2Fa::Orm::ActiveRecord::Schema

7
lib/devise_two_factor_authentication/rails.rb

@ -1,7 +0,0 @@
module DeviseTwoFactorAuthentication
class Engine < ::Rails::Engine
ActiveSupport.on_load(:action_controller) do
include DeviseTwoFactorAuthentication::Controllers::Helpers
end
end
end

3
lib/devise_two_factor_authentication/version.rb

@ -1,3 +0,0 @@
module DeviseTwoFactorAuthentication
VERSION = "3.0.0".freeze
end

18
lib/devise_two_factor_authentication.rb → lib/two_factor_authentication.rb

@ -1,4 +1,4 @@
require 'devise_two_factor_authentication/version'
require 'two_factor_authentication/version'
require 'devise'
require 'active_support/concern'
require "active_model"
@ -34,19 +34,19 @@ module Devise
@@delete_cookie_on_logout = false
end
module DeviseTwoFactorAuthentication
module TwoFactorAuthentication
NEED_AUTHENTICATION = 'need_two_factor_authentication'
REMEMBER_TFA_COOKIE_NAME = "remember_tfa"
autoload :Schema, 'devise_two_factor_authentication/schema'
autoload :Schema, 'two_factor_authentication/schema'
module Controllers
autoload :Helpers, 'devise_two_factor_authentication/controllers/helpers'
autoload :Helpers, 'two_factor_authentication/controllers/helpers'
end
end
Devise.add_module :two_factor_authenticatable, :model => 'devise_two_factor_authentication/models/two_factor_authenticatable', :controller => :two_factor_authentication, :route => :two_factor_authentication
Devise.add_module :two_factor_authenticatable, :model => 'two_factor_authentication/models/two_factor_authenticatable', :controller => :two_factor_authentication, :route => :two_factor_authentication
require 'devise_two_factor_authentication/orm/active_record' if defined?(ActiveRecord::Base)
require 'devise_two_factor_authentication/routes'
require 'devise_two_factor_authentication/models/two_factor_authenticatable'
require 'devise_two_factor_authentication/rails'
require 'two_factor_authentication/orm/active_record' if defined?(ActiveRecord::Base)
require 'two_factor_authentication/routes'
require 'two_factor_authentication/models/two_factor_authenticatable'
require 'two_factor_authentication/rails'

6
lib/devise_two_factor_authentication/controllers/helpers.rb → lib/two_factor_authentication/controllers/helpers.rb

@ -1,4 +1,4 @@
module DeviseTwoFactorAuthentication
module TwoFactorAuthentication
module Controllers
module Helpers
extend ActiveSupport::Concern
@ -12,7 +12,7 @@ module DeviseTwoFactorAuthentication
def handle_two_factor_authentication
unless devise_controller?
Devise.mappings.keys.flatten.any? do |scope|
if signed_in?(scope) and warden.session(scope)[DeviseTwoFactorAuthentication::NEED_AUTHENTICATION]
if signed_in?(scope) and warden.session(scope)[TwoFactorAuthentication::NEED_AUTHENTICATION]
handle_failed_second_factor(scope)
end
end
@ -47,7 +47,7 @@ module Devise
module Controllers
module Helpers
def is_fully_authenticated?
!session["warden.user.user.session"].try(:[], DeviseTwoFactorAuthentication::NEED_AUTHENTICATION)
!session["warden.user.user.session"].try(:[], TwoFactorAuthentication::NEED_AUTHENTICATION)
end
end
end

6
lib/devise_two_factor_authentication/hooks/two_factor_authenticatable.rb → lib/two_factor_authentication/hooks/two_factor_authenticatable.rb

@ -1,17 +1,17 @@
Warden::Manager.after_authentication do |user, auth, options|
if auth.env["action_dispatch.cookies"]
expected_cookie_value = "#{user.class}-#{user.public_send(Devise.second_factor_resource_id)}"
actual_cookie_value = auth.env["action_dispatch.cookies"].signed[DeviseTwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME]
actual_cookie_value = auth.env["action_dispatch.cookies"].signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME]
bypass_by_cookie = actual_cookie_value == expected_cookie_value
end
if user.respond_to?(:need_two_factor_authentication?) && !bypass_by_cookie
if auth.session(options[:scope])[DeviseTwoFactorAuthentication::NEED_AUTHENTICATION] = user.need_two_factor_authentication?(auth.request)
if auth.session(options[:scope])[TwoFactorAuthentication::NEED_AUTHENTICATION] = user.need_two_factor_authentication?(auth.request)
user.send_new_otp if user.send_new_otp_after_login?
end
end
end
Warden::Manager.before_logout do |user, auth, _options|
auth.cookies.delete DeviseTwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME if Devise.delete_cookie_on_logout
auth.cookies.delete TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME if Devise.delete_cookie_on_logout
end

4
lib/devise_two_factor_authentication/models/two_factor_authenticatable.rb → lib/two_factor_authentication/models/two_factor_authenticatable.rb

@ -1,4 +1,4 @@
require 'devise_two_factor_authentication/hooks/two_factor_authenticatable'
require 'two_factor_authentication/hooks/two_factor_authenticatable'
require 'rotp'
require 'encryptor'
@ -40,7 +40,7 @@ module Devise
raise "authenticate_totp called with no otp_secret_key set" if totp_secret.nil?
totp = ROTP::TOTP.new(totp_secret, digits: digits)
new_timestamp = totp.verify(
without_spaces(code),
without_spaces(code),
drift_ahead: drift, drift_behind: drift, after: totp_timestamp
)
return false unless new_timestamp

14
lib/two_factor_authentication/orm/active_record.rb

@ -0,0 +1,14 @@
require "active_record"
module TwoFactorAuthentication
module Orm
module ActiveRecord
module Schema
include TwoFactorAuthentication::Schema
end
end
end
end
ActiveRecord::ConnectionAdapters::Table.send :include, TwoFactorAuthentication::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TwoFactorAuthentication::Orm::ActiveRecord::Schema

7
lib/two_factor_authentication/rails.rb

@ -0,0 +1,7 @@
module TwoFactorAuthentication
class Engine < ::Rails::Engine
ActiveSupport.on_load(:action_controller) do
include TwoFactorAuthentication::Controllers::Helpers
end
end
end

10
lib/devise_two_factor_authentication/routes.rb → lib/two_factor_authentication/routes.rb

@ -4,16 +4,8 @@ module ActionDispatch::Routing
def devise_two_factor_authentication(mapping, controllers)
resource :two_factor_authentication, :only => [:show, :update, :resend_code], :path => mapping.path_names[:two_factor_authentication], :controller => controllers[:two_factor_authentication] do
collection { get resend_code_path(mapping), as: "resend_code" }
collection { get "resend_code" }
end
end
def resend_code_path(mapping)
Devise.mappings[resource_name(mapping)].path_names[:two_factor_authentication_resend_code] || "resend_code"
end
def resource_name(mapping)
mapping.class_name.underscore.to_sym
end
end
end

2
lib/devise_two_factor_authentication/schema.rb → lib/two_factor_authentication/schema.rb

@ -1,4 +1,4 @@
module DeviseTwoFactorAuthentication
module TwoFactorAuthentication
module Schema
def second_factor_attempts_count
apply_devise_schema :second_factor_attempts_count, Integer, :default => 0

3
lib/two_factor_authentication/version.rb

@ -0,0 +1,3 @@
module TwoFactorAuthentication
VERSION = "2.2.0".freeze
end

5
spec/rails_app/config/application.rb

@ -6,7 +6,7 @@ require "action_mailer/railtie"
require "sprockets/railtie"
Bundler.require(*Rails.groups)
require "devise_two_factor_authentication"
require "two_factor_authentication"
module Dummy
class Application < Rails::Application
@ -47,8 +47,6 @@ module Dummy
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
config.active_record.legacy_connection_handling = false
# Enable the asset pipeline
config.assets.enabled = true
@ -62,3 +60,4 @@ module Dummy
config.secret_key_base = 'secretvalue'
end
end

37
spec/rails_app/db/schema.rb

@ -2,28 +2,29 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2016_02_09_032439) do
ActiveRecord::Schema.define(version: 2016_02_09_032439) do
create_table "admins", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at", precision: nil
t.datetime "remember_created_at", precision: nil
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at", precision: nil
t.datetime "last_sign_in_at", precision: nil
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_admins_on_email", unique: true
t.index ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
end
@ -32,15 +33,15 @@ ActiveRecord::Schema[7.0].define(version: 2016_02_09_032439) do
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at", precision: nil
t.datetime "remember_created_at", precision: nil
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at", precision: nil
t.datetime "last_sign_in_at", precision: nil
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "second_factor_attempts_count", default: 0
t.string "nickname", limit: 64
t.string "encrypted_otp_secret_key"

2
spec/support/controller_helper.rb

@ -2,7 +2,7 @@ module ControllerHelper
def sign_in(user = create_user('not_encrypted'))
allow(warden).to receive(:authenticated?).with(:user).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
warden.session(:user)[DeviseTwoFactorAuthentication::NEED_AUTHENTICATION] = true
warden.session(:user)[TwoFactorAuthentication::NEED_AUTHENTICATION] = true
end
end

4
spec/support/features_spec_helper.rb

@ -20,11 +20,11 @@ module FeaturesSpecHelper
end
def set_tfa_cookie value
set_cookie DeviseTwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME, value
set_cookie TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME, value
end
def get_tfa_cookie
get_cookie DeviseTwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME
get_cookie TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME
end
end

16
devise_two_factor_authentication.gemspec → two_factor_authentication.gemspec

@ -1,14 +1,14 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "devise_two_factor_authentication/version"
require "two_factor_authentication/version"
Gem::Specification.new do |s|
s.name = "devise_two_factor_authentication"
s.version = DeviseTwoFactorAuthentication::VERSION.dup
s.authors = ["baarkerlounger"]
s.email = ["baarkerlounger@protonmail.com"]
s.homepage = "https://github.com/devise2fa/devise_two_factor_authentication"
s.summary = %q{Two factor authentication plugin for devise forked from Houdini/two_factor_authentication}
s.name = "two_factor_authentication"
s.version = TwoFactorAuthentication::VERSION.dup
s.authors = ["Dmitrii Golub"]
s.email = ["dmitrii.golub@gmail.com"]
s.homepage = "https://github.com/Houdini/two_factor_authentication"
s.summary = %q{Two factor authentication plugin for devise}
s.license = "MIT"
s.description = <<-EOF
### Features ###
@ -18,7 +18,7 @@ Gem::Specification.new do |s|
* your own sms logic
EOF
s.rubyforge_project = "devise_two_factor_authentication"
s.rubyforge_project = "two_factor_authentication"
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
Loading…
Cancel
Save