Class: WebauthnAuthenticationGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Includes:
ActiveRecord::Generators::Migration, BundleHelper, Rails::Generators::BundleHelper
Defined in:
lib/generators/webauthn_authentication/webauthn_authentication_generator.rb

Instance Method Summary collapse

Methods included from BundleHelper

#bundle_command

Instance Method Details

#copy_controllers_and_concernsObject



67
68
69
70
71
72
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 67

def copy_controllers_and_concerns
  template "app/controllers/passkeys_controller.rb"
  template "app/controllers/webauthn_sessions_controller.rb"
  template "app/controllers/second_factor_authentications_controller.rb"
  template "app/controllers/second_factor_webauthn_credentials_controller.rb"
end

#copy_initializer_fileObject



111
112
113
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 111

def copy_initializer_file
  template "config/initializers/webauthn.rb"
end

#copy_stimulus_controllersObject



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 78

def copy_stimulus_controllers
  if using_importmap? || using_bun? || has_package_json?
    template "app/javascript/controllers/webauthn_credentials_controller.js"

    if using_bun? || has_package_json?
      run "bin/rails stimulus:manifest:update"
    end
  else
    puts "You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem."
  end
end

#final_messageObject



145
146
147
148
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 145

def final_message
  say ""
  say "Almost done! Now edit `config/initializers/webauthn.rb` and set the `allowed_origins` and `rp_name` for your app.", :yellow
end

#inject_js_packagesObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 90

def inject_js_packages
  if using_importmap?
    say %(Appending: pin "@github/webauthn-json/browser-ponyfill", to: "https://ga.jspm.io/npm:@github/[email protected]/dist/esm/webauthn-json.browser-ponyfill.js")
    append_to_file "config/importmap.rb", %(pin "@github/webauthn-json/browser-ponyfill", to: "https://ga.jspm.io/npm:@github/[email protected]/dist/esm/webauthn-json.browser-ponyfill.js"\n)
  elsif using_bun?
    say "Adding webauthn-json to your package manager"
    run "bun add @github/webauthn-json/browser-ponyfill"
  elsif has_package_json?
    say "Adding webauthn-json to your package manager"
    run "yarn add @github/webauthn-json/browser-ponyfill"
  else
    puts "You must either be running with node (package.json) or importmap-rails (config/importmap.rb) to use this gem."
  end
end

#inject_to_authentication_concernObject



55
56
57
58
59
60
61
62
63
64
65
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 55

def inject_to_authentication_concern
  inject_into_file "app/controllers/concerns/authentication.rb",
    after: /def terminate_session.*?end\n/m do
      <<-RUBY.strip_heredoc.indent(4)

        def require_no_authentication
          redirect_to root_path if find_session_by_cookie
        end
      RUBY
    end
end

#inject_webauthn_contentObject



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 115

def inject_webauthn_content
  generate "migration", "AddWebauthnToUsers", "webauthn_id:string"
  inject_webauthn_content_to_user_model

  inject_into_file "config/routes.rb", after: "Rails.application.routes.draw do\n" do
    <<-RUBY.strip_heredoc.indent(2)
      resource :webauthn_session, only: [ :create, :destroy ] do
        post :get_options, on: :collection
      end

      resources :passkeys, only: [ :new, :create, :destroy ] do
        post :create_options, on: :collection
      end

      resources :second_factor_webauthn_credentials, only: [ :new, :create, :destroy ] do
        post :create_options, on: :collection
      end

      resource :second_factor_authentication, only: [ :new, :create ] do
        post :get_options, on: :collection
      end
    RUBY
  end

  template "app/models/webauthn_credential.rb"
  generate "migration", "CreateWebauthnCredentials", "user:references! external_id:string:uniq public_key:string nickname:string sign_count:integer{8} authentication_factor:integer{1}!"
end

#inject_webauthn_dependencyObject



105
106
107
108
109
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 105

def inject_webauthn_dependency
  unless File.read(File.expand_path("Gemfile", destination_root)).include?('gem "webauthn"')
    bundle_command("add webauthn", {}, quiet: true)
  end
end

#invoke_rails_authenticationObject



27
28
29
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 27

def invoke_rails_authentication
  invoke "authentication" if options.with_rails_authentication?
end

#modify_sessions_controllerObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/generators/webauthn_authentication/webauthn_authentication_generator.rb', line 31

def modify_sessions_controller
  if File.exist?(File.join(destination_root, "app/controllers/sessions_controller.rb"))
    gsub_file "app/controllers/sessions_controller.rb",
      /^  def create.*?^  end/m,
      <<~RUBY.chomp.indent(2)
        def create
          if user = User.authenticate_by(params.permit(:email_address, :password))
            if user.second_factor_enabled?
              session[:current_authentication] = { user_id: user.id }
              redirect_to new_second_factor_authentication_path
            else
              start_new_session_for user
              redirect_to after_authentication_url
            end
          else
            redirect_to new_session_path, alert: "Try another email address or password."
          end
        end
      RUBY
  else
    raise Thor::Error, "Could not find app/controllers/sessions_controller.rb. Please make sure the Rails Authentication generator was executed, or pass the --with-rails-authentication option."
  end
end