devise_instant2fa 1.0.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 +7 -0
- data/.gitignore +23 -0
- data/.rubocop.yml +295 -0
- data/.travis.yml +29 -0
- data/Gemfile +31 -0
- data/LICENSE +19 -0
- data/README.md +67 -0
- data/Rakefile +14 -0
- data/app/controllers/devise/instant2fa_controller.rb +57 -0
- data/app/views/devise/instant2fa/show.html.erb +2 -0
- data/config/locales/en.yml +7 -0
- data/devise_instant2fa.gemspec +30 -0
- data/lib/devise_instant2fa/controllers/helpers.rb +61 -0
- data/lib/devise_instant2fa/hooks/instant2fa_authenticatable.rb +11 -0
- data/lib/devise_instant2fa/rails.rb +7 -0
- data/lib/devise_instant2fa/routes.rb +10 -0
- data/lib/devise_instant2fa/version.rb +3 -0
- data/lib/devise_instant2fa/views/helpers.rb +21 -0
- data/lib/devise_instant2fa.rb +61 -0
- data/spec/spec_helper.rb +26 -0
- metadata +189 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a1b1be53c25de64e34b74a41cdd2e37a6b8cdfd9
|
4
|
+
data.tar.gz: 9314e6632e80fa4e8428a1ced354df19e461d967
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd69fe2574166de4a5925bfe95210c2968c71eb0d7affffbb80e65e2263ce47548f654069fdb708ac8a014c319b013b805fd899550d86af7c4b46e448e127613
|
7
|
+
data.tar.gz: 55950735513bcf851f970886c1bff733aafa074e2e80434003136d87706e79eeab3980c557b62a6146379ab64b4c5d052d24d36cfd3264b8b664c78faf6a164d
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
.bundle
|
3
|
+
Gemfile.lock
|
4
|
+
pkg/*
|
5
|
+
|
6
|
+
# Temporary files of every sort
|
7
|
+
.DS_Store
|
8
|
+
.idea
|
9
|
+
.rvmrc
|
10
|
+
.stgit*
|
11
|
+
*.swap
|
12
|
+
*.swo
|
13
|
+
*.swp
|
14
|
+
*~
|
15
|
+
bin/*
|
16
|
+
nbproject
|
17
|
+
patches-*
|
18
|
+
capybara-*.html
|
19
|
+
dump.rdb
|
20
|
+
*.ids
|
21
|
+
.rbenv-version
|
22
|
+
.ruby-gemset
|
23
|
+
.ruby-version
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,295 @@
|
|
1
|
+
AllCops:
|
2
|
+
Include:
|
3
|
+
- '**/Gemfile'
|
4
|
+
- '**/Rakefile'
|
5
|
+
UseCache: true
|
6
|
+
|
7
|
+
Lint/AssignmentInCondition:
|
8
|
+
Description: Don't use assignment in conditions.
|
9
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#safe-assignment-in-condition
|
10
|
+
Enabled: true
|
11
|
+
AllowSafeAssignment: true
|
12
|
+
Lint/EachWithObjectArgument:
|
13
|
+
Description: Check for immutable argument given to each_with_object.
|
14
|
+
Enabled: true
|
15
|
+
Lint/HandleExceptions:
|
16
|
+
Description: Don't suppress exception.
|
17
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions
|
18
|
+
Enabled: true
|
19
|
+
Lint/LiteralInCondition:
|
20
|
+
Description: Checks of literals used in conditions.
|
21
|
+
Enabled: true
|
22
|
+
Lint/LiteralInInterpolation:
|
23
|
+
Description: Checks for literals used in interpolation.
|
24
|
+
Enabled: true
|
25
|
+
Lint/ParenthesesAsGroupedExpression:
|
26
|
+
Description: Checks for method calls with a space before the opening parenthesis.
|
27
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#parens-no-spaces
|
28
|
+
Enabled: true
|
29
|
+
|
30
|
+
Metrics/AbcSize:
|
31
|
+
Description: A calculated magnitude based on number of assignments, branches, and
|
32
|
+
conditions.
|
33
|
+
Enabled: true
|
34
|
+
Max: 15
|
35
|
+
Exclude:
|
36
|
+
- spec/**/*
|
37
|
+
Metrics/ClassLength:
|
38
|
+
Description: Avoid classes longer than 100 lines of code.
|
39
|
+
Enabled: true
|
40
|
+
CountComments: false
|
41
|
+
Max: 100
|
42
|
+
Exclude:
|
43
|
+
- spec/**/*
|
44
|
+
Metrics/CyclomaticComplexity:
|
45
|
+
Description: A complexity metric that is strongly correlated to the number of test
|
46
|
+
cases needed to validate a method.
|
47
|
+
Enabled: true
|
48
|
+
Max: 6
|
49
|
+
Metrics/LineLength:
|
50
|
+
Description: Limit lines to 80 characters.
|
51
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#80-character-limits
|
52
|
+
Enabled: true
|
53
|
+
Max: 100
|
54
|
+
AllowURI: true
|
55
|
+
URISchemes:
|
56
|
+
- http
|
57
|
+
- https
|
58
|
+
Metrics/MethodLength:
|
59
|
+
Description: Avoid methods longer than 10 lines of code.
|
60
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#short-methods
|
61
|
+
Enabled: true
|
62
|
+
CountComments: false
|
63
|
+
Max: 10
|
64
|
+
Exclude:
|
65
|
+
- spec/**/*
|
66
|
+
Metrics/ModuleLength:
|
67
|
+
CountComments: false
|
68
|
+
Max: 100
|
69
|
+
Description: Avoid modules longer than 100 lines of code.
|
70
|
+
Enabled: true
|
71
|
+
Exclude:
|
72
|
+
- spec/**/*
|
73
|
+
Metrics/ParameterLists:
|
74
|
+
Description: Avoid parameter lists longer than three or four parameters.
|
75
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#too-many-params
|
76
|
+
Enabled: true
|
77
|
+
Max: 5
|
78
|
+
CountKeywordArgs: true
|
79
|
+
Metrics/PerceivedComplexity:
|
80
|
+
Description: A complexity metric geared towards measuring complexity for a human
|
81
|
+
reader.
|
82
|
+
Enabled: true
|
83
|
+
Max: 7
|
84
|
+
|
85
|
+
Rails/ScopeArgs:
|
86
|
+
Description: Checks the arguments of ActiveRecord scopes.
|
87
|
+
Enabled: true
|
88
|
+
Rails/TimeZone:
|
89
|
+
# The value `strict` means that `Time` should be used with `zone`.
|
90
|
+
# The value `flexible` allows usage of `in_time_zone` instead of `zone`.
|
91
|
+
Enabled: true
|
92
|
+
EnforcedStyle: flexible
|
93
|
+
SupportedStyles:
|
94
|
+
- strict
|
95
|
+
- flexible
|
96
|
+
|
97
|
+
Style/AccessorMethodName:
|
98
|
+
Description: Check the naming of accessor methods for get_/set_.
|
99
|
+
Enabled: false
|
100
|
+
Style/AndOr:
|
101
|
+
Description: Use &&/|| instead of and/or.
|
102
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-and-or-or
|
103
|
+
Enabled: true
|
104
|
+
EnforcedStyle: conditionals
|
105
|
+
SupportedStyles:
|
106
|
+
- always
|
107
|
+
- conditionals
|
108
|
+
Style/Alias:
|
109
|
+
Description: Use alias_method instead of alias.
|
110
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#alias-method
|
111
|
+
Enabled: true
|
112
|
+
Style/ClassAndModuleChildren:
|
113
|
+
EnforcedStyle: nested
|
114
|
+
SupportedStyles:
|
115
|
+
- nested
|
116
|
+
- compact
|
117
|
+
Style/CollectionMethods:
|
118
|
+
Description: Preferred collection methods.
|
119
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#map-find-select-reduce-size
|
120
|
+
Enabled: true
|
121
|
+
PreferredMethods:
|
122
|
+
collect: map
|
123
|
+
collect!: map!
|
124
|
+
find: detect
|
125
|
+
find_all: select
|
126
|
+
reduce: inject
|
127
|
+
Style/Documentation:
|
128
|
+
Description: Document classes and non-namespace modules.
|
129
|
+
Enabled: false
|
130
|
+
Style/DotPosition:
|
131
|
+
Description: Checks the position of the dot in multi-line method calls.
|
132
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-multi-line-chains
|
133
|
+
Enabled: true
|
134
|
+
EnforcedStyle: trailing
|
135
|
+
SupportedStyles:
|
136
|
+
- leading
|
137
|
+
- trailing
|
138
|
+
Style/DoubleNegation:
|
139
|
+
Description: Checks for uses of double negation (!!).
|
140
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-bang-bang
|
141
|
+
Enabled: true
|
142
|
+
Style/EachWithObject:
|
143
|
+
Description: Prefer `each_with_object` over `inject` or `reduce`.
|
144
|
+
Enabled: true
|
145
|
+
Style/EmptyLiteral:
|
146
|
+
Description: Prefer literals to Array.new/Hash.new/String.new.
|
147
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#literal-array-hash
|
148
|
+
Enabled: true
|
149
|
+
Style/FileName:
|
150
|
+
Description: Use snake_case for source file names.
|
151
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#snake-case-files
|
152
|
+
Enabled: true
|
153
|
+
Exclude: []
|
154
|
+
Style/GuardClause:
|
155
|
+
Description: Check for conditionals that can be replaced with guard clauses
|
156
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-nested-conditionals
|
157
|
+
Enabled: true
|
158
|
+
MinBodyLength: 1
|
159
|
+
Style/IfUnlessModifier:
|
160
|
+
Description: Favor modifier if/unless usage when you have a single-line body.
|
161
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#if-as-a-modifier
|
162
|
+
Enabled: false
|
163
|
+
MaxLineLength: 80
|
164
|
+
Style/InlineComment:
|
165
|
+
Description: Avoid inline comments.
|
166
|
+
Enabled: false
|
167
|
+
Style/ModuleFunction:
|
168
|
+
Description: Checks for usage of `extend self` in modules.
|
169
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#module-function
|
170
|
+
Enabled: false
|
171
|
+
Style/OneLineConditional:
|
172
|
+
Description: Favor the ternary operator(?:) over if/then/else/end constructs.
|
173
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#ternary-operator
|
174
|
+
Enabled: false
|
175
|
+
Style/OptionHash:
|
176
|
+
Description: Don't use option hashes when you can use keyword arguments.
|
177
|
+
Enabled: false
|
178
|
+
Style/PercentLiteralDelimiters:
|
179
|
+
Description: Use `%`-literal delimiters consistently
|
180
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#percent-literal-braces
|
181
|
+
Enabled: true
|
182
|
+
PreferredDelimiters:
|
183
|
+
"%": "()"
|
184
|
+
"%i": "()"
|
185
|
+
"%q": "()"
|
186
|
+
"%Q": "()"
|
187
|
+
"%r": "{}"
|
188
|
+
"%s": "()"
|
189
|
+
"%w": "()"
|
190
|
+
"%W": "()"
|
191
|
+
"%x": "()"
|
192
|
+
Style/PerlBackrefs:
|
193
|
+
Description: Avoid Perl-style regex back references.
|
194
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-perl-regexp-last-matchers
|
195
|
+
Enabled: false
|
196
|
+
Style/PredicateName:
|
197
|
+
Description: Check the names of predicate methods.
|
198
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#bool-methods-qmark
|
199
|
+
Enabled: true
|
200
|
+
NamePrefix:
|
201
|
+
- is_
|
202
|
+
- has_
|
203
|
+
- have_
|
204
|
+
NamePrefixBlacklist:
|
205
|
+
- is_
|
206
|
+
Exclude:
|
207
|
+
- spec/**/*
|
208
|
+
Style/RaiseArgs:
|
209
|
+
Description: Checks the arguments passed to raise/fail.
|
210
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#exception-class-messages
|
211
|
+
Enabled: true
|
212
|
+
EnforcedStyle: exploded
|
213
|
+
SupportedStyles:
|
214
|
+
- compact
|
215
|
+
- exploded
|
216
|
+
Style/Send:
|
217
|
+
Description: Prefer `Object#__send__` or `Object#public_send` to `send`, as `send`
|
218
|
+
may overlap with existing methods.
|
219
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#prefer-public-send
|
220
|
+
Enabled: false
|
221
|
+
Style/SignalException:
|
222
|
+
Description: Checks for proper usage of fail and raise.
|
223
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#fail-method
|
224
|
+
Enabled: true
|
225
|
+
EnforcedStyle: semantic
|
226
|
+
SupportedStyles:
|
227
|
+
- only_raise
|
228
|
+
- only_fail
|
229
|
+
- semantic
|
230
|
+
Style/SingleLineBlockParams:
|
231
|
+
Description: Enforces the names of some block params.
|
232
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#reduce-blocks
|
233
|
+
Enabled: true
|
234
|
+
Methods:
|
235
|
+
- reduce:
|
236
|
+
- a
|
237
|
+
- e
|
238
|
+
- inject:
|
239
|
+
- a
|
240
|
+
- e
|
241
|
+
Style/SingleLineMethods:
|
242
|
+
Description: Avoid single-line methods.
|
243
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-single-line-methods
|
244
|
+
Enabled: true
|
245
|
+
AllowIfMethodIsEmpty: true
|
246
|
+
Style/SpecialGlobalVars:
|
247
|
+
Description: Avoid Perl-style global variables.
|
248
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#no-cryptic-perlisms
|
249
|
+
Enabled: false
|
250
|
+
Style/StringLiterals:
|
251
|
+
Description: Checks if uses of quotes match the configured preference.
|
252
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#consistent-string-literals
|
253
|
+
Enabled: true
|
254
|
+
EnforcedStyle: single_quotes
|
255
|
+
SupportedStyles:
|
256
|
+
- single_quotes
|
257
|
+
- double_quotes
|
258
|
+
Style/StringLiteralsInInterpolation:
|
259
|
+
Description: Checks if uses of quotes inside expressions in interpolated strings
|
260
|
+
match the configured preference.
|
261
|
+
Enabled: true
|
262
|
+
EnforcedStyle: single_quotes
|
263
|
+
SupportedStyles:
|
264
|
+
- single_quotes
|
265
|
+
- double_quotes
|
266
|
+
Style/TrailingCommaInArguments:
|
267
|
+
Description: 'Checks for trailing comma in argument lists.'
|
268
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'
|
269
|
+
Enabled: true
|
270
|
+
EnforcedStyleForMultiline: no_comma
|
271
|
+
SupportedStyles:
|
272
|
+
- comma
|
273
|
+
- consistent_comma
|
274
|
+
- no_comma
|
275
|
+
Style/TrailingCommaInLiteral:
|
276
|
+
Description: 'Checks for trailing comma in array and hash literals.'
|
277
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-trailing-array-commas'
|
278
|
+
Enabled: true
|
279
|
+
EnforcedStyleForMultiline: no_comma
|
280
|
+
SupportedStyles:
|
281
|
+
- comma
|
282
|
+
- consistent_comma
|
283
|
+
- no_comma
|
284
|
+
Style/VariableInterpolation:
|
285
|
+
Description: Don't interpolate global, instance and class variables directly in
|
286
|
+
strings.
|
287
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#curlies-interpolate
|
288
|
+
Enabled: false
|
289
|
+
Style/WhenThen:
|
290
|
+
Description: Use when x then ... for one-line cases.
|
291
|
+
StyleGuide: https://github.com/bbatsov/ruby-style-guide#one-line-cases
|
292
|
+
Enabled: false
|
293
|
+
Style/ZeroLengthPredicate:
|
294
|
+
Description: 'Use #empty? when testing for objects of length 0.'
|
295
|
+
Enabled: true
|
data/.travis.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
language: ruby
|
2
|
+
|
3
|
+
env:
|
4
|
+
- "RAILS_VERSION=4.0"
|
5
|
+
- "RAILS_VERSION=4.1"
|
6
|
+
- "RAILS_VERSION=4.2"
|
7
|
+
- "RAILS_VERSION=master"
|
8
|
+
|
9
|
+
rvm:
|
10
|
+
- 2.1
|
11
|
+
- 2.2
|
12
|
+
- 2.3.1
|
13
|
+
|
14
|
+
matrix:
|
15
|
+
allow_failures:
|
16
|
+
- env: "RAILS_VERSION=master"
|
17
|
+
exclude:
|
18
|
+
- rvm: 2.1
|
19
|
+
env: RAILS_VERSION=master
|
20
|
+
- rvm: 2.2
|
21
|
+
env: RAILS_VERSION=master
|
22
|
+
|
23
|
+
before_install:
|
24
|
+
- gem update bundler
|
25
|
+
|
26
|
+
before_script:
|
27
|
+
- bundle exec rake app:db:migrate
|
28
|
+
|
29
|
+
script: bundle exec rake spec
|
data/Gemfile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in devise_ip_filter.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
rails_version = ENV["RAILS_VERSION"] || "default"
|
7
|
+
|
8
|
+
rails = case rails_version
|
9
|
+
when "master"
|
10
|
+
{github: "rails/rails"}
|
11
|
+
when "default"
|
12
|
+
"~> 4.1"
|
13
|
+
else
|
14
|
+
"~> #{rails_version}"
|
15
|
+
end
|
16
|
+
|
17
|
+
gem "rails", rails
|
18
|
+
|
19
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.2.0')
|
20
|
+
gem "test-unit", "~> 3.0"
|
21
|
+
end
|
22
|
+
|
23
|
+
group :test, :development do
|
24
|
+
gem 'sqlite3'
|
25
|
+
end
|
26
|
+
|
27
|
+
group :test do
|
28
|
+
gem 'rack_session_access'
|
29
|
+
gem 'ammeter'
|
30
|
+
gem 'pry'
|
31
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2016 Clef, Inc
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Instant 2FA for Devise
|
2
|
+
|
3
|
+
## Configuration
|
4
|
+
|
5
|
+
### Initial Setup
|
6
|
+
|
7
|
+
In a Rails environment, require the gem in your Gemfile:
|
8
|
+
|
9
|
+
gem 'devise_instant2fa'
|
10
|
+
|
11
|
+
Once that's done, run:
|
12
|
+
|
13
|
+
bundle install
|
14
|
+
|
15
|
+
Note that Ruby 2.1 or greater is required.
|
16
|
+
|
17
|
+
### Installation
|
18
|
+
|
19
|
+
#### Configuration
|
20
|
+
|
21
|
+
In order to use Instant 2FA, you'll need to configure your `access_key` and `access_secret` in the `config/initializers/devise.rb` file:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
config.instant2fa_access_key = 'YOUR_ACCESS_KEY'
|
25
|
+
config.instant2fa_access_secret = 'YOUR_ACCESS_SECRET'
|
26
|
+
```
|
27
|
+
|
28
|
+
After you've updated your configuration settings, you'll need to add the `:instant2fa_authenticatable` strategy to your user (likely in your `user.rb` file):
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
devise :instant2fa_authenticatable, :database_authenticatable, :registerable, :recoverable, :rememberable,
|
32
|
+
:trackable, :validatable
|
33
|
+
```
|
34
|
+
|
35
|
+
With those changes enabled, users who enable Instant 2FA will be prompted for verification on login.
|
36
|
+
|
37
|
+
### Customisation and Usage
|
38
|
+
|
39
|
+
#### Adding the user settings page
|
40
|
+
|
41
|
+
Instant 2FA automatically provides a hosted user settings page. This library provies view helpers to embed that page in your user experience. To use the helpers, you'll need to include the `DeviseInstant2fa::Views::Helpers` module in your `ApplicationHelpers` (or in a more specific module):
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
module ApplicationHelper
|
45
|
+
include DeviseInstant2fa::Views::Helpers
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Once this is included, you'll have access to the `instant2fa_settings_view(user)` method, which you can use in any view:
|
50
|
+
|
51
|
+
```html
|
52
|
+
<div class="two-factor-settings">
|
53
|
+
<%= instant2fa_settings_view(resource) %>
|
54
|
+
</div>
|
55
|
+
````
|
56
|
+
|
57
|
+
#### Overriding the verification view
|
58
|
+
|
59
|
+
The default view that shows the form can be overridden by adding a file named `show.html.erb` (or `show.html.haml` if you prefer HAML) inside `app/views/devise/instant2fa/` and customizing it. The important element to display is the `instant2fa_verification_form` helper.
|
60
|
+
|
61
|
+
Below is an example using ERB:
|
62
|
+
|
63
|
+
```html
|
64
|
+
<p><%= flash[:notice] %></p>
|
65
|
+
|
66
|
+
<%= instant2fa_verification_form(resource_name, @hosted_page_url)%>
|
67
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
APP_RAKEFILE = File.expand_path("../spec/rails_app/Rakefile", __FILE__)
|
4
|
+
load 'rails/tasks/engine.rake'
|
5
|
+
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
9
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
10
|
+
|
11
|
+
task :default => :spec
|
12
|
+
|
13
|
+
# To test against a specific version of Rails
|
14
|
+
# export RAILS_VERSION=3.2.0; bundle update; rake
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class Devise::Instant2faController < DeviseController
|
2
|
+
prepend_before_action :find_resource_and_require_password_checked, :only => [
|
3
|
+
:show, :update
|
4
|
+
]
|
5
|
+
|
6
|
+
def show
|
7
|
+
@hosted_page_url = session["#{resource_name}_hosted_page_url"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def update
|
11
|
+
render :show and return if params[:instant2faToken].nil?
|
12
|
+
|
13
|
+
begin
|
14
|
+
Instant2fa.confirm_verification(@resource.id.to_s, params[:instant2faToken])
|
15
|
+
after_two_factor_success_for(@resource)
|
16
|
+
rescue Instant2fa::Errors::VerificationMismatch
|
17
|
+
after_two_factor_fail_for(@resource)
|
18
|
+
rescue Instant2fa::Errors::VerificationFailed
|
19
|
+
after_two_factor_fail_for(@resource)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_resource
|
26
|
+
@resource = send("current_#{resource_name}")
|
27
|
+
|
28
|
+
if @resource.nil?
|
29
|
+
@resource = resource_class.find_by_id(session["#{resource_name}_id"])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_resource_and_require_password_checked
|
34
|
+
find_resource
|
35
|
+
|
36
|
+
if @resource.nil? || session[:"#{resource_name}_password_checked"].to_s != "true"
|
37
|
+
redirect_to invalid_resource_path
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def after_two_factor_success_for(resource)
|
42
|
+
remember_device if params[:remember_device].to_i == 1
|
43
|
+
if session.delete("#{resource_name}_remember_me") == true && resource.respond_to?(:remember_me=)
|
44
|
+
resource.remember_me = true
|
45
|
+
end
|
46
|
+
sign_in(resource_name, resource)
|
47
|
+
|
48
|
+
set_flash_message(:notice, :signed_in) if is_navigational_format?
|
49
|
+
respond_with resource, :location => after_sign_in_path_for(resource)
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_two_factor_fail_for(resource)
|
53
|
+
set_flash_message :alert, :attempt_failed, now: true
|
54
|
+
sign_out(resource)
|
55
|
+
redirect_to :root
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "devise_instant2fa/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "devise_instant2fa"
|
7
|
+
s.version = DeviseInstant2fa::VERSION.dup
|
8
|
+
s.authors = ["Jesse Pollak"]
|
9
|
+
s.email = ["jesse@instant2fa.com"]
|
10
|
+
s.homepage = "https://github.com/clef/instant2fa-devise"
|
11
|
+
s.summary = %q{Instant 2FA plugin for devise}
|
12
|
+
|
13
|
+
s.rubyforge_project = "devise_instant2fa"
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'rails', '>= 3.1.1'
|
21
|
+
s.add_runtime_dependency 'devise'
|
22
|
+
s.add_runtime_dependency 'instant2fa', '~> 1'
|
23
|
+
|
24
|
+
s.add_development_dependency 'bundler'
|
25
|
+
s.add_development_dependency 'rake'
|
26
|
+
s.add_development_dependency 'rspec-rails', '>= 3.0.1'
|
27
|
+
s.add_development_dependency 'capybara', '2.4.1'
|
28
|
+
s.add_development_dependency 'pry'
|
29
|
+
s.add_development_dependency 'timecop'
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module DeviseInstant2fa
|
2
|
+
module Controllers
|
3
|
+
module Helpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_action :handle_two_factor_authentication, :if => :is_signing_in?
|
8
|
+
end
|
9
|
+
|
10
|
+
def is_devise_sessions_controller?
|
11
|
+
self.class == Devise::SessionsController || self.class.ancestors.include?(Devise::SessionsController)
|
12
|
+
end
|
13
|
+
|
14
|
+
def is_signing_in?
|
15
|
+
if devise_controller? && signed_in?(resource_name) &&
|
16
|
+
is_devise_sessions_controller? &&
|
17
|
+
self.action_name == "create"
|
18
|
+
return true
|
19
|
+
end
|
20
|
+
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def handle_two_factor_authentication
|
27
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
28
|
+
if signed_in?(scope) and warden.session(scope)[DeviseInstant2fa::NEED_AUTHENTICATION]
|
29
|
+
check_request_and_redirect_to_verify(scope)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_request_and_redirect_to_verify(scope)
|
35
|
+
id = warden.session(resource_name)[:id]
|
36
|
+
hosted_page_url = warden.session(resource_name)[DeviseInstant2fa::HOSTED_PAGE_URL]
|
37
|
+
|
38
|
+
remember_me = (params.fetch(resource_name, {})[:remember_me].to_s == "1")
|
39
|
+
return_to = session["#{resource_name}_return_to"]
|
40
|
+
warden.logout
|
41
|
+
warden.reset_session! # make sure the session reset
|
42
|
+
|
43
|
+
session["#{resource_name}_id"] = id
|
44
|
+
session["#{resource_name}_hosted_page_url"] = hosted_page_url
|
45
|
+
# this is safe to put in the session because the cookie is signed
|
46
|
+
session["#{resource_name}_password_checked"] = true
|
47
|
+
session["#{resource_name}_remember_me"] = remember_me
|
48
|
+
session["#{resource_name}_return_to"] = return_to if return_to
|
49
|
+
|
50
|
+
redirect_to two_factor_authentication_path_for(scope)
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
def two_factor_authentication_path_for(resource_or_scope = nil)
|
55
|
+
scope = Devise::Mapping.find_scope!(resource_or_scope)
|
56
|
+
change_path = "#{scope}_two_factor_authentication_path"
|
57
|
+
send(change_path)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'instant2fa'
|
2
|
+
|
3
|
+
Warden::Manager.after_authentication do |user, auth, options|
|
4
|
+
begin
|
5
|
+
hosted_page_url = Instant2fa.create_verification(user.id.to_s)
|
6
|
+
auth.session(options[:scope])[DeviseInstant2fa::NEED_AUTHENTICATION] = true
|
7
|
+
auth.session(options[:scope])[DeviseInstant2fa::HOSTED_PAGE_URL] = hosted_page_url
|
8
|
+
auth.session(options[:scope])[:id] = user.id
|
9
|
+
rescue Instant2fa::Errors::MFANotEnabled
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module DeviseInstant2fa
|
2
|
+
module Views
|
3
|
+
module Helpers
|
4
|
+
def instant2fa_settings_view(resource)
|
5
|
+
instant2fa_javascript_tag resource.instant2fa_settings_url
|
6
|
+
end
|
7
|
+
|
8
|
+
def instant2fa_verification_form(resource_name, url)
|
9
|
+
form_tag([resource_name, :two_factor_authentication], :method => :put) do
|
10
|
+
instant2fa_javascript_tag url
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def instant2fa_javascript_tag(uri)
|
17
|
+
javascript_include_tag 'https://js.instant2fa.com/hosted.js', class: 'instant2fa-page', 'data-uri' => uri
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'devise_instant2fa/version'
|
2
|
+
require 'devise'
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
5
|
+
require 'instant2fa'
|
6
|
+
|
7
|
+
module Devise
|
8
|
+
|
9
|
+
@@instant2fa_access_key = nil
|
10
|
+
def self.instant2fa_access_key
|
11
|
+
@@instant2fa_access_key
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.instant2fa_access_key=(instant2fa_access_key)
|
15
|
+
@@instant2fa_access_key = @@instant2fa_access_key
|
16
|
+
Instant2fa.configure do |config|
|
17
|
+
config.access_key = instant2fa_access_key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
@@instant2fa_access_secret = nil
|
22
|
+
def self.instant2fa_access_secret
|
23
|
+
@@instant2fa_access_secret
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.instant2fa_access_secret=(instant2fa_access_secret)
|
27
|
+
@@instant2fa_access_secret = @@instant2fa_access_secret
|
28
|
+
Instant2fa.configure do |config|
|
29
|
+
config.access_secret = instant2fa_access_secret
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module DeviseInstant2fa
|
35
|
+
NEED_AUTHENTICATION = 'need_two_factor_authentication'
|
36
|
+
HOSTED_PAGE_URL = 'hosted_page_url'
|
37
|
+
|
38
|
+
module Controllers
|
39
|
+
autoload :Helpers, 'devise_instant2fa/controllers/helpers'
|
40
|
+
end
|
41
|
+
|
42
|
+
module Views
|
43
|
+
autoload :Helpers, 'devise_instant2fa/views/helpers'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Devise
|
48
|
+
module Models
|
49
|
+
module Instant2faAuthenticatable
|
50
|
+
def instant2fa_settings_url
|
51
|
+
Instant2fa.create_settings(self.id)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Devise.add_module :instant2fa_authenticatable, :controller => :instant2fa, :route => :instant2fa
|
58
|
+
|
59
|
+
require 'devise_instant2fa/hooks/instant2fa_authenticatable'
|
60
|
+
require 'devise_instant2fa/routes'
|
61
|
+
require 'devise_instant2fa/rails'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= "test"
|
2
|
+
require File.expand_path("../rails_app/config/environment.rb", __FILE__)
|
3
|
+
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'timecop'
|
6
|
+
require 'rack_session_access/capybara'
|
7
|
+
|
8
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
config.use_transactional_examples = true
|
14
|
+
|
15
|
+
config.include Capybara::DSL
|
16
|
+
|
17
|
+
# Run specs in random order to surface order dependencies. If you find an
|
18
|
+
# order dependency and want to debug it, you can fix the order by providing
|
19
|
+
# the seed, which is printed after each run.
|
20
|
+
# --seed 1234
|
21
|
+
config.order = 'random'
|
22
|
+
|
23
|
+
config.after(:each) { Timecop.return }
|
24
|
+
end
|
25
|
+
|
26
|
+
Dir["#{Dir.pwd}/spec/support/**/*.rb"].each {|f| require f}
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise_instant2fa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jesse Pollak
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.1.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.1.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: devise
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: instant2fa
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.0.1
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.0.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: capybara
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 2.4.1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.4.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: timecop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description:
|
140
|
+
email:
|
141
|
+
- jesse@instant2fa.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rubocop.yml"
|
148
|
+
- ".travis.yml"
|
149
|
+
- Gemfile
|
150
|
+
- LICENSE
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- app/controllers/devise/instant2fa_controller.rb
|
154
|
+
- app/views/devise/instant2fa/show.html.erb
|
155
|
+
- config/locales/en.yml
|
156
|
+
- devise_instant2fa.gemspec
|
157
|
+
- lib/devise_instant2fa.rb
|
158
|
+
- lib/devise_instant2fa/controllers/helpers.rb
|
159
|
+
- lib/devise_instant2fa/hooks/instant2fa_authenticatable.rb
|
160
|
+
- lib/devise_instant2fa/rails.rb
|
161
|
+
- lib/devise_instant2fa/routes.rb
|
162
|
+
- lib/devise_instant2fa/version.rb
|
163
|
+
- lib/devise_instant2fa/views/helpers.rb
|
164
|
+
- spec/spec_helper.rb
|
165
|
+
homepage: https://github.com/clef/instant2fa-devise
|
166
|
+
licenses: []
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project: devise_instant2fa
|
184
|
+
rubygems_version: 2.5.1
|
185
|
+
signing_key:
|
186
|
+
specification_version: 4
|
187
|
+
summary: Instant 2FA plugin for devise
|
188
|
+
test_files:
|
189
|
+
- spec/spec_helper.rb
|