Skip to content

Commit

Permalink
GRN-56: Correctly implemented the account verification flow (bigblueb…
Browse files Browse the repository at this point in the history
…utton#367)

* Correctly implemented the account verification flow

* Fixed issues with redirect locations
  • Loading branch information
farhatahmad authored and jfederico committed Feb 22, 2019
1 parent 5521402 commit c60e25f
Show file tree
Hide file tree
Showing 17 changed files with 337 additions and 141 deletions.
76 changes: 76 additions & 0 deletions app/controllers/account_activations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
#
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.

class AccountActivationsController < ApplicationController
before_action :ensure_unauthenticated
before_action :find_user

# GET /account_activations
def show
render :verify
end

# GET /account_activations/edit
def edit
if @user && !@user.email_verified? && @user.authenticated?(:activation, params[:token])
@user.activate

flash[:success] = I18n.t("verify.activated") + " " + I18n.t("verify.signin")
else
flash[:alert] = I18n.t("verify.invalid")
end

redirect_to root_url
end

# GET /account_activations/resend
def resend
if @user.email_verified
flash[:alert] = I18n.t("verify.already_verified")
else
begin
@user.send_activation_email(verification_link)
rescue => e
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent")
end
end

redirect_to(root_path)
end

private

def verification_link
request.base_url + edit_account_activation_path(token: @user.activation_token, email: @user.email)
end

def ensure_unauthenticated
redirect_to current_user.main_room if current_user
end

def email_params
params.require(:email).permit(:token)
end

def find_user
@user = User.find_by!(email: params[:email], provider: "greenlight")
end
end
18 changes: 16 additions & 2 deletions app/controllers/rooms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

class RoomsController < ApplicationController
before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms }
before_action :validate_verified_email, unless: -> { !Rails.configuration.enable_email_verification }
before_action :validate_verified_email, except: [:show, :join],
unless: -> { !Rails.configuration.enable_email_verification }
before_action :find_room, except: :create
before_action :verify_room_ownership, except: [:create, :show, :join, :logout]
before_action :verify_room_owner_verified, only: [:show, :join]

include RecordingsHelper
META_LISTED = "gl-listed"
Expand Down Expand Up @@ -240,7 +242,19 @@ def validate_accepted_terms

def validate_verified_email
if current_user
redirect_to resend_path unless current_user.email_verified
redirect_to account_activation_path(current_user) unless current_user.email_verified
end
end

def verify_room_owner_verified
unless @room.owner.email_verified
flash[:alert] = t("room.unavailable")

if current_user
redirect_to current_user.main_room
else
redirect_to root_path
end
end
end
end
6 changes: 5 additions & 1 deletion app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ def create
if user && !user.greenlight_account?
redirect_to root_path, alert: I18n.t("invalid_login_method")
elsif user.try(:authenticate, session_params[:password])
login(user)
if user.email_verified
login(user)
else
redirect_to(account_activation_path(email: user.email)) && return
end
else
redirect_to root_path, alert: I18n.t("invalid_credentials")
end
Expand Down
73 changes: 27 additions & 46 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,37 @@ def create
@user = User.new(user_params)
@user.provider = "greenlight"

if Rails.configuration.enable_email_verification && @user.save
# Check if user already exists
if User.exists?(email: user_params[:email], provider: @user.provider)
existing_user = User.find_by!(email: user_params[:email], provider: @user.provider)
if Rails.configuration.enable_email_verification && !existing_user.email_verified?
# User exists but is not verified
redirect_to(account_activation_path(email: existing_user.email)) && return
else
# User already exists and is verified
# Attempt to save so that the correct errors appear
@user.save

render(:new) && return
end
elsif Rails.configuration.enable_email_verification && @user.save
begin
UserMailer.verify_email(@user, verification_link(@user)).deliver
login(@user)
@user.send_activation_email(verification_link)
rescue => e
logger.error "Error in email delivery: #{e}"
mailer_delivery_fail
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent")
end

redirect_to(root_path) && return
elsif @user.save
# User doesn't exist and email verification is turned off
@user.activate
login(@user)
else
# Handle error on user creation.
render :new
render(:new) && return
end
end

Expand Down Expand Up @@ -145,53 +163,16 @@ def terms
end
end

# GET | POST /u/verify/confirm
def confirm
if !current_user || current_user.uid != params[:user_uid]
redirect_to '/404'
elsif current_user.email_verified
login(current_user)
elsif params[:email_verified] == "true"
current_user.update_attributes(email_verified: true)
login(current_user)
else
render 'verify'
end
end

# GET /u/verify/resend
def resend
if !current_user
redirect_to '/404'
elsif current_user.email_verified
login(current_user)
elsif params[:email_verified] == "false"
begin
UserMailer.verify_email(current_user, verification_link(current_user)).deliver
render 'verify'
rescue => e
logger.error "Error in email delivery: #{e}"
mailer_delivery_fail
end
else
render 'verify'
end
end

private

def mailer_delivery_fail
redirect_to root_path, alert: I18n.t(params[:message], default: I18n.t("delivery_error"))
end

def verification_link(user)
request.base_url + confirm_path(user.uid)
end

def find_user
@user = User.find_by!(uid: params[:user_uid])
end

def verification_link
request.base_url + edit_account_activation_path(token: @user.activation_token, email: @user.email)
end

def ensure_unauthenticated
redirect_to current_user.main_room if current_user
end
Expand Down
20 changes: 20 additions & 0 deletions app/helpers/account_activations_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
#
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.

module AccountActivationsHelper
end
32 changes: 29 additions & 3 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.

class User < ApplicationRecord
attr_accessor :reset_token
after_create :initialize_main_room
attr_accessor :reset_token, :activation_token
after_create :create_home_room_if_verified
before_save { email.try(:downcase!) }
before_create :create_activation_digest

before_destroy :destroy_rooms

Expand Down Expand Up @@ -94,6 +95,18 @@ def auth_image(auth)
end
end

# Activates an account and initialize a users main room
def activate
update_attribute(:email_verified, true)
update_attribute(:activated_at, Time.zone.now)

initialize_main_room
end

def send_activation_email(url)
UserMailer.verify_email(self, url).deliver
end

# Sets the password reset attributes.
def create_reset_digest
self.reset_token = User.new_token
Expand Down Expand Up @@ -156,14 +169,27 @@ def self.new_token

private

def create_activation_digest
# Create the token and digest.
self.activation_token = User.new_token
self.activation_digest = User.digest(activation_token)
end

# Destory a users rooms when they are removed.
def destroy_rooms
rooms.destroy_all
end

# Assigns the user a BigBlueButton id and a home room if verified
def create_home_room_if_verified
self.uid = "gl-#{(0...12).map { (65 + rand(26)).chr }.join.downcase}"

initialize_main_room if email_verified
save
end

# Initializes a room for the user and assign a BigBlueButton user id.
def initialize_main_room
self.uid = "gl-#{(0...12).map { (65 + rand(26)).chr }.join.downcase}"
self.main_room = Room.create!(owner: self, name: I18n.t("home_room"))
save
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,8 @@
<h3 class="card-title"><%= t("verify.title") %></h3>
</div>
<div class="card-body">
<p> Your account has not been verified yet. </p>
<% if Rails.configuration.enable_email_verification && params[:user_uid] == current_user.uid %>
<%= render "/shared/components/confirm_button" %>
<% else %>
<%= render "/shared/components/resend_button" %>
<% end %>
</form>
<p><%= t("verify.not_verified") %></p>
<%= render "/shared/components/resend_button" %>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/shared/components/_resend_button.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@
%>

<div class="btn-list text-right pt-8">
<%= button_to t("verify.resend"), resend_path, params: { email_verified: false }, class: "btn btn-primary btn-space" %>
<%= button_to t("verify.resend"), resend_email_path, params: { email_verified: false }, class: "btn btn-primary btn-space" %>
</div>
10 changes: 8 additions & 2 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ en:
sessions: Sessions
settings: Room Settings
start: Start
unavailable: This room is currently unavailable due to the owner's email not being verified.
update_settings_error: There was an error updating the room settings
update_settings_success: Room settings successfully updated
wait:
Expand Down Expand Up @@ -222,6 +223,11 @@ en:
For details, see the %{href}.
update: Update
verify:
title: Verify your email
resend: Resend verification email
accept: Verify
activated: Account verified!
already_verified: Account has already been verified
invalid: Invalid verification link
not_verified: Your account has not been verified yet.
resend: Resend verification email
signin: Please sign in to access your account.
title: Verify your email
13 changes: 7 additions & 6 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,15 @@
# Password reset resources.
resources :password_resets, only: [:new, :create, :edit, :update]

# Account activation resources
scope '/account_activations' do
get '/', to: 'account_activations#show', as: :account_activation
get '/edit', to: 'account_activations#edit', as: :edit_account_activation
get '/resend', to: 'account_activations#resend', as: :resend_email
end

# User resources.
scope '/u' do
# Verification Routes
scope '/verify' do
match '/resend', to: 'users#resend', via: [:get, :post], as: :resend
match '/confirm/:user_uid', to: 'users#confirm', via: [:get, :post], as: :confirm
end

# Handles login of greenlight provider accounts.
post '/login', to: 'sessions#create', as: :create_session

Expand Down
8 changes: 8 additions & 0 deletions db/migrate/20190206210049_add_activation_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

class AddActivationToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :activation_digest, :string
add_column :users, :activated_at, :datetime
end
end
Loading

0 comments on commit c60e25f

Please sign in to comment.