Class: Bible270::SessionsController

Inherits:
ApplicationController show all
Defined in:
app/controllers/bible270/sessions_controller.rb

Overview

Built-in OmniAuth sign-in.

The OmniAuth middleware (registered by the host app) handles the request and callback phases; by the time #create runs, request.env is populated and we just need to turn it into a Reader and remember them.

NOTE: OmniAuth 2.0+ only permits POST to its request-phase routes, so all sign-in controls in these views are forms/buttons rather than links.

Instance Method Summary collapse

Instance Method Details

#createObject



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

def create
  auth = request.env['omniauth.auth']
  redirect_to(, alert: "Sign in didn't complete. Please try again.") and return unless auth

  if enrollment_closed? && !Reader.omniauth_reader_exists?(auth['provider'], auth['uid'])
    redirect_to(, alert: enrollment_closed_message) and return
  end

  reader = Reader.from_omniauth(auth)
  redirect_to(, alert: "We couldn't set up your reader profile.") and return unless reader&.persisted?

  destination = safe_origin(request.env['omniauth.origin']) || 

  # Rotate the session id to avoid session fixation, then sign in.
  reset_session
  session[:bible270_reader_id] = reader.id
  @current_reader = reader

  redirect_to destination, notice: "Welcome #{reader.first_name}."
end

#destroyObject



41
42
43
44
45
# File 'app/controllers/bible270/sessions_controller.rb', line 41

def destroy
  reset_session
  @current_reader = nil
  redirect_to(after_sign_out_path, notice: 'Signed out.')
end

#email_callbackObject

GET: the reader clicked the link.



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
# File 'app/controllers/bible270/sessions_controller.rb', line 93

def email_callback
  token = SignInToken.claim!(params[:token])
  if token.nil?
    redirect_to(,
                alert: 'That link has expired or was already used. Please request a new one.') and return
  end

  if enrollment_closed? && !Reader.email_reader_exists?(token.email)
    redirect_to(, alert: enrollment_closed_message) and return
  end

  reader = Reader.from_email(token.email, first_name: token.first_name,
                                          last_name: token.last_name, display_name: token.display_name)
  redirect_to(, alert: "We couldn't set up your reader profile.") and return unless reader&.persisted?

  destination = safe_origin(params[:origin]) || 

  reset_session
  session[:bible270_reader_id] = reader.id
  @current_reader = reader

  if name_needed?(reader)
    redirect_to(profile_path,
                notice: 'Welcome. Please add your name, so others know who they are reading with.')
    return
  end

  redirect_to destination, notice: "Welcome #{reader.first_name}."
end

POST: accept an address and send a one-time link.



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
# File 'app/controllers/bible270/sessions_controller.rb', line 55

def email_link
  unless Bible270.config.email_sign_in?
    redirect_to(, alert: "Email sign-in isn't enabled here.") and return
  end

  origin  = safe_origin(params[:origin])
  address = EmailSignIn.normalize_email(params[:email])
  if address.nil?
    redirect_to((origin: origin),
                alert: "That doesn't look like an email address — please check and try again.") and return
  end

  # Names are optional here. Requiring them only for unknown addresses would
  # make the response differ, which tells a stranger whether an address
  # already has an account. A new reader is asked for their name after they
  # click the link instead (see email_callback).
  names = Names.normalize(params[:first_name], params[:last_name])

  _record, raw = SignInToken.issue!(address, first_name: names&.dig(:first_name),
                                             last_name: names&.dig(:last_name))

  if raw && enrollment_closed? && !Reader.email_reader_exists?(address)
    Rails.logger.info("[bible270] enrolment closed; no link sent to #{address}")
  elsif raw
    (address, (token: raw, origin: origin))
  else
    # Silent to the reader by design; say so in the log or this is undebuggable.
    Rails.logger.warn("[bible270] no sign-in link issued for #{address} " \
                      '(rate limited — see config.email_sign_in_max_per_window)')
  end

  # Deliberately identical whether or not a link was actually sent, so this
  # reveals neither who has an account nor that a limit was hit.
  redirect_to ,
              notice: "Check your inbox — if that address is valid we've sent a sign-in link to #{address}."
end

#failureObject



47
48
49
50
# File 'app/controllers/bible270/sessions_controller.rb', line 47

def failure
  message = params[:message].presence || 'unknown error'
  redirect_to , alert: "Sign in failed (#{message.to_s.tr('_', ' ')})."
end

#newObject



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

def new
  redirect_to(, notice: "You're already signed in.") and return if signed_in?

  @providers = Bible270.config.omniauth_providers
  @origin = safe_origin(params[:origin])
end