Module: Obscured::Doorman::Strategies::ForgotPassword

Defined in:
lib/obscured-doorman/strategies/forgot_password.rb

Class Method Summary collapse

Class Method Details

.registered(app) ⇒ Object



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
# File 'lib/obscured-doorman/strategies/forgot_password.rb', line 7

def self.registered(app)
  Warden::Manager.after_authentication do |user, auth, _opts|
    # If the user requested a new password,
    # but then remembers and logs in,
    # then invalidate password reset token
    user.remembered_password! if auth.winning_strategy.is_a?(Doorman::Strategies::Password)
  end

  app.get '/doorman/forgot/?' do
    redirect(Doorman.configuration.paths[:success]) if authenticated?

    email = cookies[:email]
    email = params[:email] if email.nil?

    haml :forgot, locals: { email: email }
  end

  app.post '/doorman/forgot' do
    redirect(Doorman.configuration.paths[:success]) if authenticated?
    redirect(Doorman.configuration.paths[:login]) unless params[:user]

    user = User.where(username: params[:user][:username]).first
    if user.nil?
      notify :error, :forgot_no_user
      redirect(back)
    else
      if user.role.to_sym == Doorman::Roles::SYSTEM
        notify :error, :reset_system_user
        redirect(Doorman.configuration.paths[:forgot])
      end

      token = user.forgot_password!
      if token.nil? && !token&.type.eql?(:password)
        notify :error, :token_not_found
        redirect(back)
      end
      if token&.used?
        notify :error, :token_used
        redirect(back)
      end

      if File.exist?('views/doorman/templates/password_reset.haml')
        template = haml :'/templates/password_reset', layout: false, locals: {
          user: user.username,
          link: token_link('reset', token.token)
        }
        Doorman::Mailer.new(
          to: user.username,
          subject: 'Password change request',
          text: "We have received a password change request for your account (#{user.username}). " + token_link('reset', token.token),
          html: template
        ).deliver!
      else
        Doorman.logger.warn "Template not found (views/doorman/templates/password_reset.haml), account password reset at #{token_link('reset', token.token)}"
      end

      notify :success, :forgot_success
      redirect(Doorman.configuration.paths[:login])
    end
  end

  app.get '/doorman/reset/:token/?' do
    redirect(Doorman.configuration.paths[:success]) if authenticated?

    if params[:token].nil? || params[:token].empty?
      notify :error, :token_not_found
      redirect(Doorman.configuration.paths[:login])
    end

    token = Token.where(token: params[:token]).first
    if token.nil?
      notify :error, :token_not_found
      redirect(Doorman.configuration.paths[:login])
    end
    if token&.used?
      notify :error, :token_used
      redirect(Doorman.configuration.paths[:login])
    end

    user = token&.user
    if user.nil?
      notify :error, :reset_no_user
      redirect(Doorman.configuration.paths[:login])
    end

    haml :reset, locals: { token: token.token, email: user&.username }
  end

  app.post '/doorman/reset' do
    redirect(Doorman.configuration.paths[:success]) if authenticated?
    redirect(Doorman.configuration.paths[:login]) unless params[:user]

    token = Token.where(token: params[:user][:token]).first
    if token.nil?
      notify :error, :token_not_found
      redirect(back)
    end
    if token&.used?
      notify :error, :token_used
      redirect(back)
    end

    user = token&.user
    if user.nil?
      notify :error, :reset_no_user
      redirect(Doorman.configuration.paths[:login])
    end

    if user&.role&.to_sym == Doorman::Roles::SYSTEM
      notify :error, :reset_system_user
      redirect(Doorman.configuration.paths[:login])
    end

    success = user&.reset_password!(
      params[:user][:password],
      params[:user][:token]
    )

    if success && File.exist?('views/doorman/templates/password_confirmation.haml')
      position = Geocoder.search(request.ip)
      template = haml :'/templates/password_confirmation', layout: false, locals: {
        user: user&.username,
        browser: "#{request&.browser} #{request&.browser_version}",
        location: "#{position&.first&.city},#{position&.first&.country}",
        ip: request&.ip,
        system: "#{request&.os} #{request&.os_version}"
      }
      Doorman::Mailer.new(
        to: user&.username,
        subject: 'Password change confirmation',
        text: "The password for your account (#{user&.username}) was recently changed. This change was made from the following device or browser from: ",
        html: template
      ).deliver!
    else
      Doorman.logger.warn "Template not found (views/doorman/templates/password_confirmation.haml) The password for your account (#{user&.username}) was recently changed."

      notify :error, :reset_unmatched_passwords
      redirect(Doorman.configuration.paths[:login])
    end

    user&.confirm!
    warden.set_user(user)
    notify :success, :reset_success

    redirect(Doorman.configuration.use_referrer && session[:return_to] ? session.delete(:return_to) : Doorman.configuration.paths[:success])
  end
end