File: login.rb

package info (click to toggle)
ruby-rodauth 2.42.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 812 kB
  • sloc: ruby: 7,524; javascript: 100; makefile: 4
file content (173 lines) | stat: -rw-r--r-- 4,888 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# frozen-string-literal: true

module Rodauth
  Feature.define(:login, :Login) do
    notice_flash "You have been logged in"
    notice_flash "Login recognized, please enter your password", "need_password"
    error_flash "There was an error logging in"
    loaded_templates %w'login login-form login-form-footer multi-phase-login login-field password-field login-display'
    view 'login', 'Login'
    view 'multi-phase-login', 'Login', 'multi_phase_login'
    additional_form_tags
    button 'Login'
    redirect

    auth_value_method :login_error_status, 401
    translatable_method :login_form_footer_links_heading, '<h2 class="rodauth-login-form-footer-links-heading">Other Options</h2>'
    auth_value_method :login_return_to_requested_location?, false
    auth_value_method :login_return_to_requested_location_max_path_size, 2048
    auth_value_method :use_multi_phase_login?, false

    session_key :login_redirect_session_key, :login_redirect

    auth_cached_method :multi_phase_login_forms
    auth_cached_method :login_form_footer

    auth_value_methods :login_return_to_requested_location_path

    auth_private_methods(
      :login_form_footer_links,
      :login_response
    )

    internal_request_method
    internal_request_method :valid_login_and_password?

    route do |r|
      check_already_logged_in
      before_login_route

      r.get do
        login_view
      end

      r.post do
        skip_error_flash = false
        view = :login_view

        catch_error do
          unless account_from_login(login_param_value)
            throw_error_reason(:no_matching_login, no_matching_login_error_status, login_param, no_matching_login_message)
          end

          before_login_attempt

          unless open_account?
            throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message)
          end

          if use_multi_phase_login?
            @valid_login_entered = true
            view = :multi_phase_login_view

            unless param_or_nil(password_param)
              after_login_entered_during_multi_phase_login
              skip_error_flash = true
              next
            end
          end

          unless password_match?(param(password_param))
            after_login_failure
            throw_error_reason(:invalid_password, login_error_status, password_param, invalid_password_message)
          end

          login('password')
        end

        set_error_flash login_error_flash unless skip_error_flash
        send(view)
      end
    end

    attr_reader :login_form_header
    attr_reader :saved_login_redirect
    private :saved_login_redirect

    def login(auth_type)
      @saved_login_redirect = remove_session_value(login_redirect_session_key)
      transaction do
        before_login
        login_session(auth_type)
        yield if block_given?
        after_login
      end
      require_response(:_login_response)
    end

    def login_required
      if login_return_to_requested_location? && (path = login_return_to_requested_location_path) && path.bytesize <= login_return_to_requested_location_max_path_size
        set_session_value(login_redirect_session_key, path)
      end
      super
    end

    def login_return_to_requested_location_path
      request.fullpath if request.get?
    end

    def after_login_entered_during_multi_phase_login
      set_notice_now_flash need_password_notice_flash
      if multi_phase_login_forms.length == 1 && (meth = multi_phase_login_forms[0][2])
        send(meth)
      end
    end

    def skip_login_field_on_login?
      return false unless use_multi_phase_login?
      valid_login_entered?
    end

    def skip_password_field_on_login?
      return false unless use_multi_phase_login?
      !valid_login_entered?
    end

    def valid_login_entered?
      @valid_login_entered
    end

    def login_hidden_field
      "<input type='hidden' name=\"#{login_param}\" value=\"#{scope.h param(login_param)}\" />"
    end

    def login_form_footer_links
      @login_form_footer_links ||= _filter_links(_login_form_footer_links)
    end

    def render_multi_phase_login_forms
      multi_phase_login_forms.sort.map{|_, form, _| form}.join("\n")
    end

    def require_login_redirect
      login_path
    end

    private

    def _login_response
      set_notice_flash login_notice_flash
      redirect(saved_login_redirect || login_redirect)
    end

    def _login_form_footer_links
      []
    end

    def _multi_phase_login_forms
      forms = []
      forms << [10, render("login-form"), nil] if has_password?
      forms
    end

    def _login_form_footer
      return '' if _login_form_footer_links.empty?
      render('login-form-footer')
    end

    def _login(auth_type)
      warn("Deprecated #_login method called, use #login instead.")
      login(auth_type)
    end
  end
end