devise_castle 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/app/controllers/devise/devise_castle_controller.rb +60 -0
- data/app/controllers/devise/two_factor_authentication_controller.rb +3 -0
- data/app/controllers/devise_castle/sessions_controller.rb +17 -0
- data/app/views/devise/two_factor_authentication/authenticator/edit.html.erb +14 -0
- data/app/views/devise/two_factor_authentication/sms/edit.html.erb +17 -0
- data/app/views/devise/two_factor_authentication/yubikey/edit.html.erb +14 -0
- data/lib/devise_castle.rb +29 -0
- data/lib/devise_castle/controllers/helpers.rb +29 -0
- data/lib/devise_castle/hooks.rb +50 -0
- data/lib/devise_castle/import.rb +85 -0
- data/lib/devise_castle/mapping.rb +14 -0
- data/lib/devise_castle/model.rb +52 -0
- data/lib/devise_castle/railtie.rb +11 -0
- data/lib/devise_castle/routes.rb +9 -0
- data/lib/devise_castle/version.rb +3 -0
- data/lib/generators/active_record/devise_castle_generator.rb +14 -0
- data/lib/generators/active_record/templates/migration.rb +13 -0
- data/lib/generators/devise_castle/devise_castle_generator.rb +18 -0
- data/lib/generators/devise_castle/import_generator.rb +12 -0
- data/lib/generators/devise_castle/install_generator.rb +32 -0
- data/lib/generators/devise_castle/views_generator.rb +18 -0
- data/lib/generators/mongoid/devise_castle_generator.rb +8 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e509c6594a298c779e9e682385bca11b4731ed22
|
4
|
+
data.tar.gz: fba122942aeaf4b8a4875284fb65a34d14e507f7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ca5a1d49f20a03317dba378c8017b51d314bc209d49eed7b21b646782325a7661556097aa05a46df143f32bff77c836ee6b1290f9a08ea8122c9f4044c005ca5
|
7
|
+
data.tar.gz: 3683b87fbbce2fdb04a9ce8fc090686a0f055d885586f2bf36eb2d5d1dcec9d5eb22c8dcee4b322851dfb89762c009bc29a4a29b3b52ab497deb2263b40e66d3
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class Devise::DeviseCastleController < DeviseController
|
2
|
+
include Devise::Controllers::Helpers
|
3
|
+
|
4
|
+
before_filter :return_not_found, except: :new
|
5
|
+
|
6
|
+
before_filter do
|
7
|
+
env['castle.skip_authorization'] = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
challenge = castle.challenges.create
|
12
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
13
|
+
redirect_to send(
|
14
|
+
"edit_#{scope}_two_factor_authentication_path", challenge.id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def edit
|
19
|
+
@challenge = castle.challenges.find(params[:id])
|
20
|
+
|
21
|
+
# Prevent "undefined method `errors' for nil:NilClass"
|
22
|
+
self.resource = resource_class.new
|
23
|
+
|
24
|
+
render action: "#{@challenge.delivery_method}/edit"
|
25
|
+
end
|
26
|
+
|
27
|
+
def update
|
28
|
+
challenge_id = params.require(:challenge_id)
|
29
|
+
code = params.require(:code)
|
30
|
+
|
31
|
+
begin
|
32
|
+
castle.challenges.verify(challenge_id, response: code)
|
33
|
+
|
34
|
+
castle.trust_device if params[:trust_device]
|
35
|
+
|
36
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
37
|
+
redirect_to after_sign_in_path_for(scope)
|
38
|
+
end
|
39
|
+
rescue Castle::Error
|
40
|
+
sign_out_with_message(:no_retries_remaining, :alert)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def sign_out_with_message(message, kind = :notice)
|
47
|
+
signed_out = sign_out(resource_name)
|
48
|
+
set_flash_message kind, message if signed_out
|
49
|
+
redirect_to after_sign_out_path_for(resource_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def return_not_found
|
55
|
+
unless castle.mfa_in_progress?
|
56
|
+
redirect_to after_sign_in_path_for(resource_name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class DeviseCastle::SessionsController < Devise::SessionsController
|
2
|
+
unloadable unless Rails.version =~/^4/
|
3
|
+
|
4
|
+
protected
|
5
|
+
|
6
|
+
def auth_options
|
7
|
+
# find the username
|
8
|
+
key = serialize_options(resource)[:methods].first
|
9
|
+
username = sign_in_params[key]
|
10
|
+
|
11
|
+
# find the user if any
|
12
|
+
user = resource_class.find_for_authentication(key => username)
|
13
|
+
|
14
|
+
# make it available to Warden hooks
|
15
|
+
super.merge(username: username, user: user)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h2><%= t "devise.two_factor_authentication.header" %></h2>
|
2
|
+
|
3
|
+
<p><%= t "devise.two_factor_authentication.edit.authenticator.instructions" %></p>
|
4
|
+
|
5
|
+
<%= form_tag([resource_name, :two_factor_authentication], :method => :put) do %>
|
6
|
+
<%= devise_error_messages! %>
|
7
|
+
<p><%= label_tag :code, t("devise.two_factor_authentication.edit.common.code_label") %><br />
|
8
|
+
<%= text_field_tag :code %></p>
|
9
|
+
<p><%= check_box_tag :trust_device %> <%= label_tag :trust_device %></p>
|
10
|
+
<%= hidden_field_tag(:challenge_id, @challenge.id) %>
|
11
|
+
<p><%= submit_tag t("devise.two_factor_authentication.edit.common.submit_button") %></p>
|
12
|
+
<% end -%>
|
13
|
+
|
14
|
+
<p><%= t "devise.two_factor_authentication.edit.common.recovery_message" %>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<h2><%= t "devise.two_factor_authentication.header" %></h2>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<%= t "devise.two_factor_authentication.edit.sms.instructions" %>
|
5
|
+
<%= link_to t("devise.two_factor_authentication.edit.sms.resend"), send("new_#{resource_name}_two_factor_authentication_path") %>.
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<%= form_tag([resource_name, :two_factor_authentication], :method => :put) do %>
|
9
|
+
<%= devise_error_messages! %>
|
10
|
+
<p><%= label_tag :code, t("devise.two_factor_authentication.edit.common.code_label") %><br />
|
11
|
+
<%= text_field_tag :code %></p>
|
12
|
+
<p><%= check_box_tag :trust_device %> <%= label_tag :trust_device %></p>
|
13
|
+
<%= hidden_field_tag(:challenge_id, @challenge.id) %>
|
14
|
+
<p><%= submit_tag t("devise.two_factor_authentication.edit.common.submit_button") %></p>
|
15
|
+
<% end -%>
|
16
|
+
|
17
|
+
<p><%= t "devise.two_factor_authentication.edit.common.recovery_message" %>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h2><%= t "devise.two_factor_authentication.header" %></h2>
|
2
|
+
|
3
|
+
<p><%= t "devise.two_factor_authentication.edit.yubikey.instructions" %></p>
|
4
|
+
|
5
|
+
<%= form_tag([resource_name, :two_factor_authentication], :method => :put) do %>
|
6
|
+
<%= devise_error_messages! %>
|
7
|
+
<p><%= label_tag :code, t("devise.two_factor_authentication.edit.common.code_label") %><br />
|
8
|
+
<%= text_field_tag :code %></p>
|
9
|
+
<p><%= check_box_tag :trust_device %> <%= label_tag :trust_device %></p>
|
10
|
+
<%= hidden_field_tag(:challenge_id, @challenge.id) %>
|
11
|
+
<p><%= submit_tag t("devise.two_factor_authentication.edit.common.submit_button") %></p>
|
12
|
+
<% end -%>
|
13
|
+
|
14
|
+
<p><%= t "devise.two_factor_authentication.edit.common.recovery_message" %>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'devise'
|
3
|
+
require 'devise_castle/hooks'
|
4
|
+
require 'devise_castle/routes'
|
5
|
+
require 'devise_castle/hooks'
|
6
|
+
require 'devise_castle/import'
|
7
|
+
require 'devise_castle/mapping'
|
8
|
+
require 'castle'
|
9
|
+
|
10
|
+
module Devise
|
11
|
+
mattr_accessor :castle_api_secret
|
12
|
+
@@castle_api_secret = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
module DeviseCastle
|
16
|
+
module Controllers
|
17
|
+
autoload :Helpers, 'devise_castle/controllers/helpers'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if defined?(Rails::Railtie)
|
22
|
+
require 'devise_castle/railtie'
|
23
|
+
Rails::Engine
|
24
|
+
end
|
25
|
+
|
26
|
+
Devise.add_module(:castle,
|
27
|
+
:controller => :two_factor_authentication,
|
28
|
+
:route => :castle,
|
29
|
+
:model => 'devise_castle/model')
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module DeviseCastle
|
2
|
+
module Controllers
|
3
|
+
module Helpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
rescue_from Castle::UserUnauthorizedError do |error|
|
8
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
9
|
+
warden.logout(scope)
|
10
|
+
throw :warden, :scope => scope, :message => :signed_out
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
rescue_from Castle::ChallengeRequiredError do |error|
|
15
|
+
Devise.mappings.keys.flatten.any? do |scope|
|
16
|
+
if request.format.present? and request.format.html?
|
17
|
+
session["#{scope}_return_to"] = request.path if request.get?
|
18
|
+
# todo: doesn't seem to work
|
19
|
+
redirect_to send("new_#{scope}_two_factor_authentication_path")
|
20
|
+
else
|
21
|
+
render nothing: true, status: :unauthorized
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Instantiate Castle client on every request
|
2
|
+
Warden::Manager.on_request do |warden|
|
3
|
+
warden.request.env['castle'] =
|
4
|
+
Castle::Client.new(warden.request, warden.cookies)
|
5
|
+
end
|
6
|
+
|
7
|
+
# Track logout.succeeded
|
8
|
+
Warden::Manager.before_logout do |record, warden, opts|
|
9
|
+
if record.respond_to?(:castle_id)
|
10
|
+
castle = warden.request.env['castle']
|
11
|
+
castle.logout
|
12
|
+
castle.track(user_id: record._castle_id, name: '$logout.succeeded')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Track login.failed
|
17
|
+
Warden::Manager.before_failure do |env, opts|
|
18
|
+
if opts[:action] == 'unauthenticated' && opts[:username]
|
19
|
+
|
20
|
+
user_id = if opts[:user].respond_to?(:castle_id)
|
21
|
+
opts[:user]._castle_id
|
22
|
+
end
|
23
|
+
|
24
|
+
castle = env['castle']
|
25
|
+
castle.track(
|
26
|
+
name: '$login.failed',
|
27
|
+
user_id: user_id,
|
28
|
+
details: {
|
29
|
+
'$login' => opts[:username]
|
30
|
+
})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Track login.succeeded
|
35
|
+
Warden::Manager.after_set_user :except => :fetch do |record, warden, opts|
|
36
|
+
if record.respond_to?(:castle_id)
|
37
|
+
castle = warden.request.env['castle']
|
38
|
+
castle.track(user_id: record._castle_id, name: '$login.succeeded')
|
39
|
+
castle.login(record._castle_id, email: record.email)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Continous authentication
|
44
|
+
Warden::Manager.after_set_user do |record, warden, opts|
|
45
|
+
if record.respond_to?(:castle_id)
|
46
|
+
env = warden.request.env
|
47
|
+
castle = env['castle']
|
48
|
+
castle.authorize! unless env['castle.skip_authorization']
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module DeviseCastle
|
2
|
+
class ImportError < Exception; end
|
3
|
+
|
4
|
+
class Import
|
5
|
+
attr_reader :resource_class, :batch_size
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
begin
|
9
|
+
@resource_class = eval(options[:resource_class])
|
10
|
+
rescue NameError
|
11
|
+
raise ImportError, "No such class: #{options[:resource_class]}"
|
12
|
+
end
|
13
|
+
|
14
|
+
unless supported_orm?
|
15
|
+
raise ImportError, "Only ActiveRecord and Mongoid models are supported"
|
16
|
+
end
|
17
|
+
|
18
|
+
unless Castle.config.api_secret.present?
|
19
|
+
raise ImportError, "Please add an Castle API secret to your devise.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
@batch_size = [(options[:batch_size] || 100), 100].min
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.run(*args)
|
26
|
+
new(*args).run
|
27
|
+
end
|
28
|
+
|
29
|
+
def run
|
30
|
+
batches do |batch, resources|
|
31
|
+
begin
|
32
|
+
users = Castle::User.import(users: batch)
|
33
|
+
rescue Castle::Error => error
|
34
|
+
raise ImportError, error.message
|
35
|
+
end
|
36
|
+
|
37
|
+
users.zip(resources).each do |user, resource|
|
38
|
+
resource.castle_id = user.id
|
39
|
+
resource.save(validate: false)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def batches
|
45
|
+
if active_record?
|
46
|
+
resource_class.where("castle_id IS NULL").find_in_batches(:batch_size => batch_size) do |resources|
|
47
|
+
resources_for_wire = map_resources_to_castle_format(resources)
|
48
|
+
yield(resources_for_wire, resources) unless resources.count.zero?
|
49
|
+
end
|
50
|
+
elsif mongoid?
|
51
|
+
0.step(resource_class.where(:castle_id => nil).count, batch_size) do |offset|
|
52
|
+
resources_for_wire = map_resources_to_castle_format(resource_class.limit(batch_size).skip(offset))
|
53
|
+
yield(resources_for_wire, resources) unless resources.count.zero?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def map_resources_to_castle_format(resources)
|
59
|
+
resources.map do |resource|
|
60
|
+
format = {}
|
61
|
+
format[:email] = resource.email unless resource.email.blank?
|
62
|
+
format[:id] = resource._castle_id
|
63
|
+
format[:created_at] = resource.created_at if resource.respond_to? :created_at
|
64
|
+
format
|
65
|
+
end.compact
|
66
|
+
end
|
67
|
+
|
68
|
+
def prepare_batch(batch)
|
69
|
+
{ :users => batch }.to_json
|
70
|
+
end
|
71
|
+
|
72
|
+
def active_record?
|
73
|
+
(defined?(ActiveRecord::Base) && (resource_class < ActiveRecord::Base))
|
74
|
+
end
|
75
|
+
|
76
|
+
def mongoid?
|
77
|
+
(defined?(Mongoid::Document) && (resource_class < Mongoid::Document))
|
78
|
+
end
|
79
|
+
|
80
|
+
def supported_orm?
|
81
|
+
active_record? || mongoid?
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module DeviseCastle
|
2
|
+
module Mapping
|
3
|
+
def self.included(base)
|
4
|
+
base.alias_method_chain :default_controllers, :castle
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def default_controllers_with_castle(options)
|
9
|
+
options[:controllers] ||= {}
|
10
|
+
options[:controllers][:sessions] ||= "devise_castle/sessions"
|
11
|
+
default_controllers_without_castle(options)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
module Castle
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
::Castle.api_secret = Devise.castle_api_secret
|
7
|
+
|
8
|
+
included do
|
9
|
+
before_destroy :destroy_castle_user
|
10
|
+
|
11
|
+
def destroy_castle_user
|
12
|
+
castle_user_block do
|
13
|
+
::Castle::User.destroy_existing(id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def castle_user_block
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
rescue ::Castle::Error
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Override this in your Devise model to use a custom identifier
|
26
|
+
# for the Castle API:s
|
27
|
+
def castle_id
|
28
|
+
id
|
29
|
+
end
|
30
|
+
|
31
|
+
# Since the identifier will be used in API routes, it needs to be
|
32
|
+
# URI encoded
|
33
|
+
def _castle_id
|
34
|
+
URI.encode(castle_id.to_s)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Overwrites valid_for_authentication? from Devise::Models::Authenticatable
|
39
|
+
# for verifying whether a user is allowed to sign in or not.
|
40
|
+
def valid_for_authentication?
|
41
|
+
return super unless persisted?
|
42
|
+
|
43
|
+
if super
|
44
|
+
true
|
45
|
+
else
|
46
|
+
# TODO: track unsuccessful login
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module ActionDispatch::Routing
|
2
|
+
class Mapper
|
3
|
+
protected
|
4
|
+
|
5
|
+
def devise_castle(mapping, controllers)
|
6
|
+
resources :two_factor_authentication, :only => [:new, :show, :update, :edit], :path => mapping.path_names[:two_factor_authentication], :controller => controllers[:two_factor_authentication]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Generators
|
5
|
+
class DeviseCastleGenerator < ActiveRecord::Generators::Base
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
def copy_devise_castle_migration
|
9
|
+
migration_template "migration.rb", "db/migrate/add_castle_to_#{table_name}.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AddCastleTo<%= table_name.camelize %> < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
change_table :<%= table_name %> do |t|
|
4
|
+
t.string :castle_id
|
5
|
+
end
|
6
|
+
|
7
|
+
add_index :<%= table_name %>, :castle_id, :unique => true
|
8
|
+
end
|
9
|
+
|
10
|
+
def down
|
11
|
+
remove_column :<%= table_name %>, :castle_id
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DeviseCastle
|
2
|
+
module Generators
|
3
|
+
class DeviseCastleGenerator < Rails::Generators::NamedBase
|
4
|
+
namespace "devise_castle"
|
5
|
+
|
6
|
+
desc "Add :castle directive in the given model. Also generate migration for ActiveRecord"
|
7
|
+
|
8
|
+
def inject_devise_castle_content
|
9
|
+
path = File.join("app", "models", "#{file_path}.rb")
|
10
|
+
if File.exists?(path)
|
11
|
+
inject_into_file(path, "castle, :", :after => "devise :")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
hook_for :orm
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DeviseCastle
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../../templates", __FILE__)
|
5
|
+
desc "Add DeviseCastle config variables to the Devise initializer"
|
6
|
+
argument :api_secret, :desc => "Your Castle API secret, which can be found on your Castle dashboard."
|
7
|
+
|
8
|
+
def add_config_options_to_initializer
|
9
|
+
devise_initializer_path = "config/initializers/devise.rb"
|
10
|
+
if File.exist?(devise_initializer_path)
|
11
|
+
old_content = File.read(devise_initializer_path)
|
12
|
+
|
13
|
+
if old_content.match(Regexp.new(/^\s*# ==> Configuration for :castle\n/))
|
14
|
+
false
|
15
|
+
else
|
16
|
+
inject_into_file(devise_initializer_path, :before => " # ==> Mailer Configuration\n") do
|
17
|
+
<<-CONTENT
|
18
|
+
# ==> Configuration for :castle
|
19
|
+
config.castle_api_secret = '#{api_secret}'
|
20
|
+
|
21
|
+
CONTENT
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_locale
|
28
|
+
copy_file "../../../config/locales/en.yml", "config/locales/devise_castle.en.yml"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'generators/devise/views_generator'
|
2
|
+
|
3
|
+
module DeviseCastle
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Rails::Generators::Base
|
6
|
+
desc 'Copies all DeviseCastle views to your application.'
|
7
|
+
|
8
|
+
argument :scope, :required => false, :default => nil,
|
9
|
+
:desc => "The scope to copy views to"
|
10
|
+
|
11
|
+
include ::Devise::Generators::ViewPathTemplates
|
12
|
+
source_root File.expand_path("../../../../app/views/devise", __FILE__)
|
13
|
+
def copy_views
|
14
|
+
view_directory :two_factor_authentication
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devise_castle
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Johan Brissmyr
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: devise
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: castle-rb
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.0.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.1.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.1'
|
83
|
+
description: Devise extension for Castle. Secure your authentication stack with real-time
|
84
|
+
monitoring, instantly notifying you and your users on potential account hijacks.
|
85
|
+
email: johan@castle.io
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- app/controllers/devise/devise_castle_controller.rb
|
91
|
+
- app/controllers/devise/two_factor_authentication_controller.rb
|
92
|
+
- app/controllers/devise_castle/sessions_controller.rb
|
93
|
+
- app/views/devise/two_factor_authentication/authenticator/edit.html.erb
|
94
|
+
- app/views/devise/two_factor_authentication/sms/edit.html.erb
|
95
|
+
- app/views/devise/two_factor_authentication/yubikey/edit.html.erb
|
96
|
+
- lib/devise_castle.rb
|
97
|
+
- lib/devise_castle/controllers/helpers.rb
|
98
|
+
- lib/devise_castle/hooks.rb
|
99
|
+
- lib/devise_castle/import.rb
|
100
|
+
- lib/devise_castle/mapping.rb
|
101
|
+
- lib/devise_castle/model.rb
|
102
|
+
- lib/devise_castle/railtie.rb
|
103
|
+
- lib/devise_castle/routes.rb
|
104
|
+
- lib/devise_castle/version.rb
|
105
|
+
- lib/generators/active_record/devise_castle_generator.rb
|
106
|
+
- lib/generators/active_record/templates/migration.rb
|
107
|
+
- lib/generators/devise_castle/devise_castle_generator.rb
|
108
|
+
- lib/generators/devise_castle/import_generator.rb
|
109
|
+
- lib/generators/devise_castle/install_generator.rb
|
110
|
+
- lib/generators/devise_castle/views_generator.rb
|
111
|
+
- lib/generators/mongoid/devise_castle_generator.rb
|
112
|
+
homepage: https://github.com/castle/devise_castle
|
113
|
+
licenses:
|
114
|
+
- MIT
|
115
|
+
metadata: {}
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
require_paths:
|
119
|
+
- lib
|
120
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 2.4.3
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Devise extension for Castle
|
136
|
+
test_files: []
|