forked from External/greenlight
		
	* <Added password reset system> * <Added rspec tests> * <Fixed code style> * <Added rescue for invalid smtp configuration>
This commit is contained in:
		
							
								
								
									
										90
									
								
								app/controllers/password_resets_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								app/controllers/password_resets_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
# 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 PasswordResetsController < ApplicationController
 | 
			
		||||
  before_action :disable_password_reset, unless: -> { Rails.configuration.enable_email_verification }
 | 
			
		||||
  before_action :find_user,   only: [:edit, :update]
 | 
			
		||||
  before_action :valid_user, only: [:edit, :update]
 | 
			
		||||
  before_action :check_expiration, only: [:edit, :update]
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    @user = User.find_by(email: params[:password_reset][:email].downcase)
 | 
			
		||||
    if @user
 | 
			
		||||
      @user.create_reset_digest
 | 
			
		||||
      @user.send_password_reset_email(request.base_url)
 | 
			
		||||
      redirect_to root_url, notice: I18n.t("email_sent")
 | 
			
		||||
    else
 | 
			
		||||
      redirect_to new_password_reset_path, notice: I18n.t("no_user_email_exists")
 | 
			
		||||
    end
 | 
			
		||||
  rescue => e
 | 
			
		||||
    logger.error "Error in email delivery: #{e}"
 | 
			
		||||
    redirect_to root_path, notice: I18n.t(params[:message], default: I18n.t("delivery_error"))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def edit
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    if params[:user][:password].empty?
 | 
			
		||||
      flash.now[:notice] = I18n.t("password_empty_notice")
 | 
			
		||||
      render 'edit'
 | 
			
		||||
    elsif params[:user][:password] != params[:user][:password_confirmation]
 | 
			
		||||
      flash.now[:notice] = I18n.t("password_different_notice")
 | 
			
		||||
      render 'edit'
 | 
			
		||||
    elsif current_user.update_attributes(user_params)
 | 
			
		||||
      redirect_to root_path, notice: I18n.t("password_reset_success")
 | 
			
		||||
    else
 | 
			
		||||
      render 'edit'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def find_user
 | 
			
		||||
    @user = User.find_by(email: params[:email])
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def current_user
 | 
			
		||||
    @user
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def user_params
 | 
			
		||||
    params.require(:user).permit(:password, :password_confirmation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Checks expiration of reset token.
 | 
			
		||||
  def check_expiration
 | 
			
		||||
    if current_user.password_reset_expired?
 | 
			
		||||
      redirect_to new_password_reset_url, notice: I18n.t("expired_reset_token")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Confirms a valid user.
 | 
			
		||||
  def valid_user
 | 
			
		||||
    unless current_user&.email_verified && current_user.authenticated?(:reset, params[:id])
 | 
			
		||||
      redirect_to root_url
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable_password_reset
 | 
			
		||||
    redirect_to '/404'
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										20
									
								
								app/helpers/password_resets_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/helpers/password_resets_helper.rb
									
									
									
									
									
										Normal file
									
								
							@@ -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 PasswordResetsHelper
 | 
			
		||||
end
 | 
			
		||||
@@ -24,4 +24,10 @@ class UserMailer < ApplicationMailer
 | 
			
		||||
    @url = url
 | 
			
		||||
    mail(to: @user.email, subject: t('landing.welcome'))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def password_reset(user, url)
 | 
			
		||||
    @user = user
 | 
			
		||||
    @url = url
 | 
			
		||||
    mail to: user.email, subject: t('reset_password.subtitle')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
class User < ApplicationRecord
 | 
			
		||||
  attr_accessor :reset_token
 | 
			
		||||
  after_create :initialize_main_room
 | 
			
		||||
  before_save { email.try(:downcase!) }
 | 
			
		||||
 | 
			
		||||
@@ -93,6 +94,30 @@ class User < ApplicationRecord
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Sets the password reset attributes.
 | 
			
		||||
  def create_reset_digest
 | 
			
		||||
    self.reset_token = User.new_token
 | 
			
		||||
    update_attribute(:reset_digest,  User.digest(reset_token))
 | 
			
		||||
    update_attribute(:reset_sent_at, Time.zone.now)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Sends password reset email.
 | 
			
		||||
  def send_password_reset_email(url)
 | 
			
		||||
    UserMailer.password_reset(self, url).deliver_now
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns true if the given token matches the digest.
 | 
			
		||||
  def authenticated?(attribute, token)
 | 
			
		||||
    digest = send("#{attribute}_digest")
 | 
			
		||||
    return false if digest.nil?
 | 
			
		||||
    BCrypt::Password.new(digest).is_password?(token)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Return true if password reset link expires
 | 
			
		||||
  def password_reset_expired?
 | 
			
		||||
    reset_sent_at < 2.hours.ago
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Retrives a list of all a users rooms that are not the main room, sorted by last session date.
 | 
			
		||||
  def secondary_rooms
 | 
			
		||||
    secondary = (rooms - [main_room])
 | 
			
		||||
@@ -119,6 +144,16 @@ class User < ApplicationRecord
 | 
			
		||||
    provider == "greenlight"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.digest(string)
 | 
			
		||||
    cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
 | 
			
		||||
    BCrypt::Password.create(string, cost: cost)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a random token.
 | 
			
		||||
  def self.new_token
 | 
			
		||||
    SecureRandom.urlsafe_base64
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  # Destory a users rooms when they are removed.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										50
									
								
								app/views/password_resets/edit.html.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								app/views/password_resets/edit.html.erb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
			
		||||
<%
 | 
			
		||||
# 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/>.
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
<% unless flash.empty? %>
 | 
			
		||||
  <%= render "shared/error_banner" do %>
 | 
			
		||||
    <% flash.each do |key, value| %>
 | 
			
		||||
      <%= content_tag :div, value, class: "flash #{key} d-inline" %>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<div class="container">
 | 
			
		||||
  <div class="row pt-7">
 | 
			
		||||
    <div class="col col-4 offset-4">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-header background">
 | 
			
		||||
          <h4 class="mt-2"><%= t("reset_password.subtitle") %></h4>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body background">
 | 
			
		||||
          <%= form_for(@user, url: password_reset_path(params[:id])) do |f| %>
 | 
			
		||||
 | 
			
		||||
            <%= hidden_field_tag :email, @user.email %>
 | 
			
		||||
 | 
			
		||||
            <%= f.label t('reset_password.password'), class: "form-label" %>
 | 
			
		||||
            <%= f.password_field :password, class: 'form-control' %>
 | 
			
		||||
            <br>
 | 
			
		||||
 | 
			
		||||
            <%= f.label t('reset_password.confirm'), class: "form-label" %>
 | 
			
		||||
            <%= f.password_field :password_confirmation, class: 'form-control' %>
 | 
			
		||||
            <br>
 | 
			
		||||
 | 
			
		||||
            <%= f.submit t('reset_password.update'), class: "btn btn-primary" %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										43
									
								
								app/views/password_resets/new.html.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/views/password_resets/new.html.erb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
<%
 | 
			
		||||
# 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/>.
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
<% unless flash.empty? %>
 | 
			
		||||
  <%= render "shared/error_banner" do %>
 | 
			
		||||
    <% flash.each do |key, value| %>
 | 
			
		||||
      <%= content_tag :div, value, class: "flash #{key} d-inline" %>
 | 
			
		||||
    <% end %>
 | 
			
		||||
  <% end %>
 | 
			
		||||
<% end %>
 | 
			
		||||
 | 
			
		||||
<div class="container">
 | 
			
		||||
  <div class="row pt-7">
 | 
			
		||||
    <div class="col col-4 offset-4">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-header background">
 | 
			
		||||
          <h4 class="mt-2"><%= t("forgot_password.subtitle") %></h4>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body background">
 | 
			
		||||
          <%= form_for(:password_reset, url: password_resets_path) do |f| %>
 | 
			
		||||
            <%= f.label t("forgot_password.email"), class: "form-label" %>
 | 
			
		||||
            <%= f.email_field :email, class: "form-control" %>
 | 
			
		||||
            <br>
 | 
			
		||||
      
 | 
			
		||||
            <%= f.submit t("forgot_password.submit"), class: "btn btn-primary" %>
 | 
			
		||||
          <% end %>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -55,6 +55,13 @@
 | 
			
		||||
                <%= f.password_field :password, class: "form-control", placeholder: t("password"), value: "" %>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <% if Rails.configuration.enable_email_verification %>
 | 
			
		||||
              <div class="form-group">
 | 
			
		||||
                <div class="input-icon">
 | 
			
		||||
                  <%= link_to t("modal.login.forgot_password"), new_password_reset_path %>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            <% end %>
 | 
			
		||||
            <div class="form-footer">
 | 
			
		||||
              <%= f.submit t("login"), class: "btn btn-outline-primary btn-block btn-pill" %>
 | 
			
		||||
            </div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								app/views/user_mailer/password_reset.html.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/views/user_mailer/password_reset.html.erb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
			
		||||
<%
 | 
			
		||||
# 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/>.
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
<h1>Password reset</h1>
 | 
			
		||||
 | 
			
		||||
<p>Please click the link below to reset your password:</p>
 | 
			
		||||
 | 
			
		||||
<%= link_to "Reset password", edit_password_reset_url(@user.reset_token,
 | 
			
		||||
                                                      email: @user.email,
 | 
			
		||||
                                                      host: @url) %>
 | 
			
		||||
 | 
			
		||||
<p>This link will expire in two hours.</p>
 | 
			
		||||
 | 
			
		||||
<p>
 | 
			
		||||
If you did not request your password to be reset, please ignore this email and
 | 
			
		||||
your password will not be changed.
 | 
			
		||||
</p>
 | 
			
		||||
							
								
								
									
										26
									
								
								app/views/user_mailer/password_reset.text.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/views/user_mailer/password_reset.text.erb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
<%
 | 
			
		||||
# 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/>.
 | 
			
		||||
%>
 | 
			
		||||
 | 
			
		||||
Please click the link below to reset your password:
 | 
			
		||||
 | 
			
		||||
<%= edit_password_reset_url(@user.reset_token, email: @user.email, host: @url) %>
 | 
			
		||||
 | 
			
		||||
This link will expire in two hours.
 | 
			
		||||
 | 
			
		||||
If you did not request your password to be reset, please ignore this email and
 | 
			
		||||
your password will not be changed.
 | 
			
		||||
@@ -29,6 +29,7 @@ en:
 | 
			
		||||
  delivery_error: An error occured during email delivery. Please contact an administrator!
 | 
			
		||||
  docs: Documentation
 | 
			
		||||
  email: Email
 | 
			
		||||
  email_sent: Email Sent!
 | 
			
		||||
  enter_your_name: Enter your name!
 | 
			
		||||
  errors:
 | 
			
		||||
    internal:
 | 
			
		||||
@@ -49,6 +50,7 @@ en:
 | 
			
		||||
    unprocessable:
 | 
			
		||||
      message: Oops! Request is unprocessable.
 | 
			
		||||
      help: Unforunately this isn't a valid request.
 | 
			
		||||
  expired_reset_token: Password reset link has expired!
 | 
			
		||||
  features:
 | 
			
		||||
    title: Features
 | 
			
		||||
    rooms: Personalized Rooms
 | 
			
		||||
@@ -57,6 +59,10 @@ en:
 | 
			
		||||
    authentication: User Authentication
 | 
			
		||||
  footer:
 | 
			
		||||
    powered_by: Powered by %{href}.
 | 
			
		||||
  forgot_password:
 | 
			
		||||
    subtitle: Forgot Password
 | 
			
		||||
    email: Email
 | 
			
		||||
    submit: Submit
 | 
			
		||||
  go_back: Go back
 | 
			
		||||
  greenlight: Greenlight
 | 
			
		||||
  header:
 | 
			
		||||
@@ -109,13 +115,18 @@ en:
 | 
			
		||||
    login:
 | 
			
		||||
      or: or
 | 
			
		||||
      with: Sign in with %{provider}
 | 
			
		||||
      forgot_password: Forgot Password?
 | 
			
		||||
    rename_recording:
 | 
			
		||||
 | 
			
		||||
    rename_room:
 | 
			
		||||
      name_placeholder: Enter a new room name...
 | 
			
		||||
  name_update_success: Room name successfully changed!
 | 
			
		||||
  no_user_email_exists: There is no existing user with the email specified. Please make sure you typed it correctly.
 | 
			
		||||
  omniauth_error: An error occured while authenticating with omniauth. Please try again or contact an administrator!
 | 
			
		||||
  password: Password
 | 
			
		||||
  password_empty_notice: Password cannot be empty.
 | 
			
		||||
  password_reset_success: Password has been reset.
 | 
			
		||||
  password_different_notice: Password Confirmation does not match.
 | 
			
		||||
  provider:
 | 
			
		||||
    google: Google
 | 
			
		||||
    microsoft_office365: Office 365
 | 
			
		||||
@@ -136,6 +147,11 @@ en:
 | 
			
		||||
      public: Public
 | 
			
		||||
      unlisted: Unlisted
 | 
			
		||||
  rename: Rename
 | 
			
		||||
  reset_password:
 | 
			
		||||
    subtitle: Reset Password
 | 
			
		||||
    password: New Password
 | 
			
		||||
    confirm: New Password Confirmation
 | 
			
		||||
    update: Update Password
 | 
			
		||||
  room:
 | 
			
		||||
    invited: You have been invited to join
 | 
			
		||||
    invite_participants: Invite Participants
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,9 @@ Rails.application.routes.draw do
 | 
			
		||||
  # Redirect to terms page
 | 
			
		||||
  match '/terms', to: 'users#terms', via: [:get, :post]
 | 
			
		||||
 | 
			
		||||
  # Password reset resources.
 | 
			
		||||
  resources :password_resets, only: [:new, :create, :edit, :update]
 | 
			
		||||
 | 
			
		||||
  # User resources.
 | 
			
		||||
  scope '/u' do
 | 
			
		||||
    # Verification Routes
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								db/migrate/20181217142710_add_reset_to_users.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								db/migrate/20181217142710_add_reset_to_users.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
# 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 AddResetToUsers < ActiveRecord::Migration[5.0]
 | 
			
		||||
  def change
 | 
			
		||||
    add_column :users, :reset_digest, :string
 | 
			
		||||
    add_column :users, :reset_sent_at, :datetime
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 20181113174230) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 20181217142710) do
 | 
			
		||||
 | 
			
		||||
  create_table "rooms", force: :cascade do |t|
 | 
			
		||||
    t.integer  "user_id"
 | 
			
		||||
@@ -40,10 +40,13 @@ ActiveRecord::Schema.define(version: 20181113174230) do
 | 
			
		||||
    t.string   "image"
 | 
			
		||||
    t.string   "password_digest"
 | 
			
		||||
    t.boolean  "accepted_terms",  default: false
 | 
			
		||||
    t.datetime "created_at",                          null: false
 | 
			
		||||
    t.datetime "updated_at",                          null: false
 | 
			
		||||
    t.datetime "created_at",                            null: false
 | 
			
		||||
    t.datetime "updated_at",                            null: false
 | 
			
		||||
    t.boolean  "email_verified",  default: false
 | 
			
		||||
    t.string   "language",        default: "default"
 | 
			
		||||
    t.string   "role",            default: "moderator"
 | 
			
		||||
    t.string   "reset_digest"
 | 
			
		||||
    t.datetime "reset_sent_at"
 | 
			
		||||
    t.index ["password_digest"], name: "index_users_on_password_digest", unique: true
 | 
			
		||||
    t.index ["room_id"], name: "index_users_on_room_id"
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										138
									
								
								spec/controllers/password_resets_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								spec/controllers/password_resets_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,138 @@
 | 
			
		||||
# 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/>.
 | 
			
		||||
 | 
			
		||||
require "rails_helper"
 | 
			
		||||
 | 
			
		||||
def random_valid_user_params
 | 
			
		||||
  pass = Faker::Internet.password(8)
 | 
			
		||||
  {
 | 
			
		||||
    user: {
 | 
			
		||||
      name: Faker::Name.first_name,
 | 
			
		||||
      email: Faker::Internet.email,
 | 
			
		||||
      password: pass,
 | 
			
		||||
      password_confirmation: pass,
 | 
			
		||||
      accepted_terms: true,
 | 
			
		||||
      email_verified: true,
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
describe PasswordResetsController, type: :controller do
 | 
			
		||||
  describe "POST #create" do
 | 
			
		||||
    context "allow mail notifications" do
 | 
			
		||||
      before { allow(Rails.configuration).to receive(:enable_email_verification).and_return(true) }
 | 
			
		||||
 | 
			
		||||
      it "redirects to root url if email is sent" do
 | 
			
		||||
        user = create(:user)
 | 
			
		||||
 | 
			
		||||
        params = {
 | 
			
		||||
          password_reset: {
 | 
			
		||||
            email: user.email,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        post :create, params: params
 | 
			
		||||
        expect(response).to redirect_to(root_path)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it "reloads the page if no email exists in the database" do
 | 
			
		||||
        params = {
 | 
			
		||||
          password_reset: {
 | 
			
		||||
            email: nil,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        post :create, params: params
 | 
			
		||||
        expect(response).to redirect_to(new_password_reset_path)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context "does not allow mail notifications" do
 | 
			
		||||
      before { allow(Rails.configuration).to receive(:enable_email_verification).and_return(false) }
 | 
			
		||||
 | 
			
		||||
      it "renders a 404 page upon if email notifications are disabled" do
 | 
			
		||||
        get :create
 | 
			
		||||
        expect(response).to redirect_to("/404")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe "PATCH #update" do
 | 
			
		||||
    before { allow(Rails.configuration).to receive(:enable_email_verification).and_return(true) }
 | 
			
		||||
 | 
			
		||||
    context "valid user" do
 | 
			
		||||
      it "reloads page with notice if password is empty" do
 | 
			
		||||
        token = "reset_token"
 | 
			
		||||
 | 
			
		||||
        controller.stub(:valid_user).and_return(nil)
 | 
			
		||||
        controller.stub(:check_expiration).and_return(nil)
 | 
			
		||||
 | 
			
		||||
        params = {
 | 
			
		||||
          id: token,
 | 
			
		||||
          user: {
 | 
			
		||||
            password: nil,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        patch :update, params: params
 | 
			
		||||
        expect(response).to render_template(:edit)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it "reloads page with notice if password is confirmation doesn't match" do
 | 
			
		||||
        token = "reset_token"
 | 
			
		||||
 | 
			
		||||
        controller.stub(:valid_user).and_return(nil)
 | 
			
		||||
        controller.stub(:check_expiration).and_return(nil)
 | 
			
		||||
 | 
			
		||||
        params = {
 | 
			
		||||
          id: token,
 | 
			
		||||
          user: {
 | 
			
		||||
            password: :password,
 | 
			
		||||
            password_confirmation: nil,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        patch :update, params: params
 | 
			
		||||
        expect(response).to render_template(:edit)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      it "updates attributes if the password update is a success" do
 | 
			
		||||
        user = create(:user)
 | 
			
		||||
        token = "reset_token"
 | 
			
		||||
 | 
			
		||||
        cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
 | 
			
		||||
        user.reset_digest = BCrypt::Password.create(token, cost: cost)
 | 
			
		||||
 | 
			
		||||
        controller.stub(:valid_user).and_return(nil)
 | 
			
		||||
        controller.stub(:check_expiration).and_return(nil)
 | 
			
		||||
        controller.stub(:current_user).and_return(user)
 | 
			
		||||
 | 
			
		||||
        params = {
 | 
			
		||||
          id: token,
 | 
			
		||||
          user: {
 | 
			
		||||
            password: :password,
 | 
			
		||||
            password_confirmation: :password,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        patch :update, params: params
 | 
			
		||||
        expect(response).to redirect_to(root_path)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -109,4 +109,21 @@ describe User, type: :model do
 | 
			
		||||
      expect(user.name_chunk).to eq("exa")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  context 'password reset' do
 | 
			
		||||
    it 'creates token and respective reset digest' do
 | 
			
		||||
      user = create(:user)
 | 
			
		||||
 | 
			
		||||
      reset_digest_success = user.create_reset_digest
 | 
			
		||||
      expect(reset_digest_success).to eq(true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'verifies if password reset link expired' do
 | 
			
		||||
      user = create(:user)
 | 
			
		||||
      user.create_reset_digest
 | 
			
		||||
 | 
			
		||||
      expired = user.password_reset_expired?
 | 
			
		||||
      expect(expired).to be_in([true, false])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user