Class: RivetCms::SessionsController

Inherits:
AuthController show all
Defined in:
app/controllers/rivet_cms/sessions_controller.rb

Constant Summary collapse

LOGIN_ATTEMPT_LIMIT =
10
LOGIN_ATTEMPT_WINDOW =
5.minutes

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.dummy_digestObject

Memoized on the class, computed on first use so BCrypt is referenced at request time (after bcrypt is required), never at load time



8
9
10
# File 'app/controllers/rivet_cms/sessions_controller.rb', line 8

def self.dummy_digest
  @dummy_digest ||= BCrypt::Password.create("rivet-cms-timing-equalizer").to_s
end

Instance Method Details

#createObject



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'app/controllers/rivet_cms/sessions_controller.rb', line 19

def create
  # Reserve an attempt atomically BEFORE authenticating, so a parallel
  # burst cannot slip every request through BCrypt before any counter
  # reaches the limit. The increment is the reservation.
  unless reserve_attempt
    return redirect_to ,
                       inertia: { errors: { base: [ "Too many attempts. Wait a few minutes and try again" ] } }
  end

  user = users.active.find_by(email: )
  if user&.can_sign_in? && user.authenticate(params[:password].to_s)
    release_reservation_on_success
    (user)
    redirect_to root_path
  else
    equalize_timing unless user&.can_sign_in?
    # Failure keeps its reservation; that is the point of the counters
    redirect_to , inertia: { errors: { base: [ "That email and password combination does not work" ] } }
  end
end

#destroyObject



40
41
42
43
# File 'app/controllers/rivet_cms/sessions_controller.rb', line 40

def destroy
  reset_session
  redirect_to , status: :see_other
end

#newObject



12
13
14
15
16
17
# File 'app/controllers/rivet_cms/sessions_controller.rb', line 12

def new
  return redirect_to root_path if builtin_session_user
  return redirect_to setup_path if users.none?

  render inertia: "Auth/Login", props: { submit_path:  }
end