GRN2-180: First stages of refactoring code for v2.4 (#748)

* Email rescues and authenticator concern

* Application controller and helper clean up

* Moved controller code out of helpers

* More helper and email clean up

* Cleaned up remaining helpers and create omniauth_options

* Controller code clean up

* restructured views structure

* Restructured role code

* Restructured profile and code clean up

* Master merge

* Added bbb server concern to deal with bbb calls

* Bug fixes and changes after changes

* rspec

* More rubocop fixes
v2
farhatahmad 4 years ago committed by farhatahmad
parent 194b5ddfa0
commit fd6077696d
  1. 8
      app/assets/javascripts/admins.js
  2. 31
      app/controllers/account_activations_controller.rb
  3. 197
      app/controllers/admins_controller.rb
  4. 216
      app/controllers/application_controller.rb
  5. 70
      app/controllers/concerns/authenticator.rb
  6. 109
      app/controllers/concerns/bbb_server.rb
  7. 109
      app/controllers/concerns/emailer.rb
  8. 14
      app/controllers/concerns/recorder.rb
  9. 12
      app/controllers/concerns/registrar.rb
  10. 161
      app/controllers/concerns/rolify.rb
  11. 37
      app/controllers/password_resets_controller.rb
  12. 12
      app/controllers/recordings_controller.rb
  13. 128
      app/controllers/rooms_controller.rb
  14. 89
      app/controllers/sessions_controller.rb
  15. 7
      app/controllers/themes_controller.rb
  16. 141
      app/controllers/users_controller.rb
  17. 20
      app/helpers/account_activations_helper.rb
  18. 30
      app/helpers/admins_helper.rb
  19. 69
      app/helpers/application_helper.rb
  20. 20
      app/helpers/errors_helper.rb
  21. 20
      app/helpers/main_helper.rb
  22. 20
      app/helpers/meetings_helper.rb
  23. 20
      app/helpers/password_resets_helper.rb
  24. 7
      app/helpers/recordings_helper.rb
  25. 18
      app/helpers/rooms_helper.rb
  26. 17
      app/helpers/theming_helper.rb
  27. 29
      app/helpers/users_helper.rb
  28. 1
      app/mailers/application_mailer.rb
  29. 57
      app/mailers/user_mailer.rb
  30. 3
      app/models/ability.rb
  31. 106
      app/models/room.rb
  32. 9
      app/models/user.rb
  33. 4
      app/views/account_activations/show.html.erb
  34. 0
      app/views/admins/components/_admins_role.html.erb
  35. 0
      app/views/admins/components/_admins_tags.html.erb
  36. 30
      app/views/admins/components/_settings.html.erb
  37. 4
      app/views/admins/components/_users.html.erb
  38. 2
      app/views/admins/edit_user.html.erb
  39. 0
      app/views/main/components/_features.html.erb
  40. 2
      app/views/main/index.html.erb
  41. 0
      app/views/rooms/components/_create_room_block.html.erb
  42. 0
      app/views/rooms/components/_room_block.html.erb
  43. 0
      app/views/rooms/components/_room_event.html.erb
  44. 4
      app/views/rooms/join.html.erb
  45. 10
      app/views/rooms/show.html.erb
  46. 2
      app/views/rooms/wait.html.erb
  47. 18
      app/views/shared/components/_confirm_button.html.erb
  48. 18
      app/views/shared/components/_resend_button.html.erb
  49. 13
      app/views/shared/components/_subtitle.html.erb
  50. 18
      app/views/shared/components/_terms_button.html.erb
  51. 4
      app/views/shared/modals/_delete_room_modal.html.erb
  52. 26
      app/views/users/change_password.html.erb
  53. 0
      app/views/users/components/_account.html.erb
  54. 0
      app/views/users/components/_delete.html.erb
  55. 26
      app/views/users/components/_menu_buttons.html.erb
  56. 0
      app/views/users/components/_password.html.erb
  57. 4
      app/views/users/components/_setting_view.html.erb
  58. 10
      app/views/users/delete_account.html.erb
  59. 37
      app/views/users/edit.html.erb
  60. 4
      app/views/users/terms.html.erb
  61. 5
      config/initializers/omniauth.rb
  62. 10
      config/locales/en.yml
  63. 26
      config/routes.rb
  64. 71
      lib/omniauth_options.rb
  65. 88
      spec/concerns/bbb_server_spec.rb
  66. 32
      spec/concerns/recorder_spec.rb
  67. 2
      spec/controllers/account_activations_controller_spec.rb
  68. 30
      spec/controllers/admins_controller_spec.rb
  69. 64
      spec/controllers/application_controller_spec.rb
  70. 6
      spec/controllers/password_resets_controller_spec.rb
  71. 12
      spec/controllers/recordings_controller_spec.rb
  72. 25
      spec/controllers/rooms_controller_spec.rb
  73. 3
      spec/controllers/users_controller_spec.rb
  74. 44
      spec/helpers/admins_helper_spec.rb
  75. 62
      spec/helpers/application_helper_spec.rb
  76. 44
      spec/helpers/users_helper_spec.rb
  77. 74
      spec/models/room_spec.rb

@ -79,7 +79,7 @@ $(document).on('turbolinks:load', function(){
// Change the branding image to the image provided
function changeBrandingImage(path) {
var url = $("#branding-url").val()
$.post(path, {url: url})
$.post(path, {value: url})
}
// Filters by role
@ -157,19 +157,19 @@ function loadColourSelectors() {
});
pickrRegular.on("save", (color, instance) => {
$.post($("#coloring-path-regular").val(), {color: color.toHEXA().toString()}).done(function() {
$.post($("#coloring-path-regular").val(), {value: color.toHEXA().toString()}).done(function() {
location.reload()
});
})
pickrLighten.on("save", (color, instance) => {
$.post($("#coloring-path-lighten").val(), {color: color.toHEXA().toString()}).done(function() {
$.post($("#coloring-path-lighten").val(), {value: color.toHEXA().toString()}).done(function() {
location.reload()
});
})
pickrDarken.on("save", (color, instance) => {
$.post($("#coloring-path-darken").val(), {color: color.toHEXA().toString()}).done(function() {
$.post($("#coloring-path-darken").val(), {value: color.toHEXA().toString()}).done(function() {
location.reload()
});
})

@ -24,46 +24,45 @@ class AccountActivationsController < ApplicationController
# GET /account_activations
def show
render :verify
end
# GET /account_activations/edit
def edit
# If the user exists and is not verified and provided the correct token
if @user && !@user.activated? && @user.authenticated?(:activation, params[:token])
# Verify user
@user.activate
# Redirect user to root with account pending flash if account is still pending
return redirect_to root_path,
flash: { success: I18n.t("registration.approval.signup") } if @user.has_role?(:pending)
flash[:success] = I18n.t("verify.activated") + " " + I18n.t("verify.signin")
redirect_to signin_path
# Redirect user to sign in path with success flash
redirect_to signin_path, flash: { success: I18n.t("verify.activated") + " " + I18n.t("verify.signin") }
else
flash[:alert] = I18n.t("verify.invalid")
redirect_to root_path
redirect_to root_path, flash: { alert: I18n.t("verify.invalid") }
end
end
# GET /account_activations/resend
def resend
if @user.activated?
# User is already verified
flash[:alert] = I18n.t("verify.already_verified")
else
begin
send_activation_email(@user)
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
# Resend
send_activation_email(@user)
end
redirect_to(root_path)
redirect_to root_path
end
private
def find_user
@user = User.find_by!(email: params[:email], provider: @user_domain)
end
def ensure_unauthenticated
redirect_to current_user.main_room if current_user
end
@ -71,8 +70,4 @@ class AccountActivationsController < ApplicationController
def email_params
params.require(:email).permit(:email, :token)
end
def find_user
@user = User.find_by!(email: params[:email], provider: @user_domain)
end
end

@ -21,18 +21,17 @@ class AdminsController < ApplicationController
include Themer
include Emailer
include Recorder
include Rolify
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve, :reset]
site_settings = [:branding, :coloring, :coloring_lighten, :coloring_darken,
:registration_method, :room_authentication, :room_limit, :default_recording_visibility]
authorize_resource class: false
before_action :find_user, only: manage_users
before_action :verify_admin_of_user, only: manage_users
before_action :find_setting, only: site_settings
# GET /admins
def index
# Initializa the data manipulation variables
@search = params[:search] || ""
@order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
@order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
@ -49,13 +48,14 @@ class AdminsController < ApplicationController
# GET /admins/server_recordings
def server_recordings
server_rooms = if Rails.configuration.loadbalanced_configuration
Room.includes(:owner).where(users: { provider: user_settings_provider }).pluck(:bbb_id)
Room.includes(:owner).where(users: { provider: @user_domain }).pluck(:bbb_id)
else
Room.pluck(:bbb_id)
end
@search, @order_column, @order_direction, recs =
all_recordings(server_rooms, @user_domain, params.permit(:search, :column, :direction), true, true)
all_recordings(server_rooms, params.permit(:search, :column, :direction), true, true)
@pagy, @recordings = pagy_array(recs)
end
@ -92,17 +92,10 @@ class AdminsController < ApplicationController
def invite
emails = params[:invite_user][:email].split(",")
begin
emails.each do |email|
invitation = create_or_update_invite(email)
emails.each do |email|
invitation = create_or_update_invite(email)
send_invitation_email(current_user.name, email, invitation.invite_token)
end
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("administrator.flash.invite", email: emails.join(', '))
send_invitation_email(current_user.name, email, invitation.invite_token)
end
redirect_to admins_path
@ -118,39 +111,30 @@ class AdminsController < ApplicationController
end
# SITE SETTINGS
# POST /admins/branding
def branding
@settings.update_value("Branding Image", params[:url])
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/update_settings
def update_settings
@settings.update_value(params[:setting], params[:value])
# POST /admins/color
def coloring
@settings.update_value("Primary Color", params[:color])
@settings.update_value("Primary Color Lighten", color_lighten(params[:color]))
@settings.update_value("Primary Color Darken", color_darken(params[:color]))
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
flash_message = I18n.t("administrator.flash.settings")
def coloring_lighten
@settings.update_value("Primary Color Lighten", params[:color])
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
if params[:value] == "Default Recording Visibility"
flash_message += ". " + I18n.t("administrator.site_settings.recording_visibility.warning")
end
def coloring_darken
@settings.update_value("Primary Color Darken", params[:color])
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
redirect_to admin_site_settings_path, flash: { success: flash_message }
end
# POST /admins/room_authentication
def room_authentication
@settings.update_value("Room Authentication", params[:value])
# POST /admins/color
def coloring
@settings.update_value("Primary Color", params[:value])
@settings.update_value("Primary Color Lighten", color_lighten(params[:value]))
@settings.update_value("Primary Color Darken", color_darken(params[:value]))
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/registration_method/:method
def registration_method
new_method = Rails.configuration.registration_methods[params[:method].to_sym]
new_method = Rails.configuration.registration_methods[params[:value].to_sym]
# Only allow change to Join by Invitation if user has emails enabled
if !Rails.configuration.enable_email_verification && new_method == Rails.configuration.registration_methods[:invite]
@ -163,67 +147,19 @@ class AdminsController < ApplicationController
end
end
# POST /admins/room_limit
def room_limit
@settings.update_value("Room Limit", params[:limit])
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/default_recording_visibility
def default_recording_visibility
@settings.update_value("Default Recording Visibility", params[:visibility])
redirect_to admin_site_settings_path, flash: {
success: I18n.t("administrator.flash.settings") + ". " +
I18n.t("administrator.site_settings.recording_visibility.warning")
}
end
# POST /admins/clear_cache
def clear_cache
Rails.cache.delete("#{@user_domain}/getUser")
Rails.cache.delete("#{@user_domain}/getUserGreenlightCredentials")
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# ROLES
# GET /admins/roles
def roles
@roles = Role.editable_roles(@user_domain)
if @roles.count.zero?
Role.create_default_roles(@user_domain)
@roles = Role.editable_roles(@user_domain)
end
@selected_role = if params[:selected_role].nil?
@roles.find_by(name: 'user')
else
@roles.find(params[:selected_role])
end
@roles = all_roles(params[:selected_role])
end
# POST /admin/role
# This method creates a new role scope to the users provider
# POST /admins/role
# This method creates a new role scoped to the users provider
def new_role
new_role_name = params[:role][:name]
new_role = create_role(params[:role][:name])
# Make sure that the role name isn't a duplicate or a reserved name like super_admin
if Role.duplicate_name(new_role_name, @user_domain)
flash[:alert] = I18n.t("administrator.roles.duplicate_name")
return redirect_to admin_roles_path
end
# Make sure the role name isn't empty
if new_role_name.strip.empty?
flash[:alert] = I18n.t("administrator.roles.empty_name")
return redirect_to admin_roles_path
end
new_role = Role.create_new_role(new_role_name, @user_domain)
return redirect_to admin_roles_path, flash: { alert: I18n.t("administrator.roles.invalid_create") } if new_role.nil?
redirect_to admin_roles_path(selected_role: new_role.id)
end
@ -232,82 +168,16 @@ class AdminsController < ApplicationController
# This updates the priority of a site's roles
# Note: A lower priority role will always get used before a higher priority one
def change_role_order
user_role = Role.find_by(name: "user", provider: @user_domain)
admin_role = Role.find_by(name: "admin", provider: @user_domain)
current_user_role = current_user.highest_priority_role
# Users aren't allowed to update the priority of the admin or user roles
if params[:role].include?(user_role.id.to_s) || params[:role].include?(admin_role.id.to_s)
flash[:alert] = I18n.t("administrator.roles.invalid_order")
return redirect_to admin_roles_path
end
# Restrict users to only updating the priority for roles in their domain with a higher
# priority
params[:role].each do |id|
role = Role.find(id)
if role.priority <= current_user_role.priority || role.provider != @user_domain
flash[:alert] = I18n.t("administrator.roles.invalid_update")
return redirect_to admin_roles_path
end
end
# Update the roles priority including the user role
top_priority = 0
params[:role].each_with_index do |id, index|
new_priority = index + [current_user_role.priority, 0].max + 1
top_priority = new_priority
Role.where(id: id).update_all(priority: new_priority)
unless update_priority(params[:role])
redirect_to admin_roles_path, flash: { alert: I18n.t("administrator.roles.invalid_order") }
end
user_role.priority = top_priority + 1
user_role.save!
end
# POST /admin/role/:role_id
# This method updates the permissions assigned to a role
def update_role
role = Role.find(params[:role_id])
current_user_role = current_user.highest_priority_role
# Checks that it is valid for the provider to update the role
if role.priority <= current_user_role.priority || role.provider != @user_domain
flash[:alert] = I18n.t("administrator.roles.invalid_update")
return redirect_to admin_roles_path(selected_role: role.id)
end
role_params = params.require(:role).permit(:name)
permission_params = params.require(:role)
.permit(
:can_create_rooms,
:send_promoted_email,
:send_demoted_email,
:can_edit_site_settings,
:can_edit_roles,
:can_manage_users,
:colour
)
# Role is a default role so users can't change the name
role_params[:name] = role.name if Role::RESERVED_ROLE_NAMES.include?(role.name)
# Make sure if the user is updating the role name that the role name is valid
if role.name != role_params[:name] && !Role.duplicate_name(role_params[:name], @user_domain) &&
!role_params[:name].strip.empty?
role.name = role_params[:name]
elsif role.name != role_params[:name]
flash[:alert] = I18n.t("administrator.roles.duplicate_name")
return redirect_to admin_roles_path(selected_role: role.id)
end
role.update(permission_params)
role.save!
flash[:alert] = I18n.t("administrator.roles.invalid_update") unless update_permissions(role)
redirect_to admin_roles_path(selected_role: role.id)
end
@ -337,10 +207,7 @@ class AdminsController < ApplicationController
@user = User.where(uid: params[:user_uid]).includes(:roles).first
end
def find_setting
@settings = Setting.find_or_create_by!(provider: user_settings_provider)
end
# Verifies that admin is an administrator of the user in the action
def verify_admin_of_user
redirect_to admins_path,
flash: { alert: I18n.t("administrator.flash.unauthorized") } unless current_user.admin_of?(@user)
@ -355,7 +222,7 @@ class AdminsController < ApplicationController
end
if Rails.configuration.loadbalanced_configuration
initial_list.where(provider: user_settings_provider)
initial_list.where(provider: @user_domain)
.admins_search(@search, @role)
.admins_order(@order_column, @order_direction)
else

@ -16,64 +16,74 @@
# 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 'bigbluebutton_api'
class ApplicationController < ActionController::Base
include ApplicationHelper
include SessionsHelper
include BbbServer
include ThemingHelper
# Force SSL for loadbalancer configurations.
before_action :redirect_to_https
before_action :set_user_domain
before_action :set_user_settings
before_action :maintenance_mode?
before_action :migration_error?
before_action :set_locale
before_action :user_locale
before_action :check_admin_password
before_action :check_user_role
# Manually handle BigBlueButton errors
rescue_from BigBlueButton::BigBlueButtonException, with: :handle_bigbluebutton_error
protect_from_forgery with: :exception
protect_from_forgery with: :exceptions
MEETING_NAME_LIMIT = 90
USER_NAME_LIMIT = 32
# Retrieves the current user.
def current_user
@current_user ||= User.where(id: session[:user_id]).includes(:roles).first
# Include user domain in lograge logs
def append_info_to_payload(payload)
super
payload[:host] = @user_domain
if Rails.configuration.loadbalanced_configuration
if @current_user && !@current_user.has_role?(:super_admin) &&
@current_user.provider != @user_domain
@current_user = nil
session.clear
end
end
@current_user
end
helper_method :current_user
# Show an information page when migration fails and there is a version error.
def migration_error?
render :migration_error, status: 500 unless ENV["DB_MIGRATE_FAILED"].blank?
def bbb_server
@bbb_server ||= Rails.configuration.loadbalanced_configuration ? bbb(@user_domain) : bbb("greenlight")
end
def maintenance_mode?
if Rails.configuration.maintenance_mode
render "errors/greenlight_error", status: 503, formats: :html,
locals: {
status_code: 503,
message: I18n.t("errors.maintenance.message"),
help: I18n.t("errors.maintenance.help"),
}
# Force SSL
def redirect_to_https
if Rails.configuration.loadbalanced_configuration && request.headers["X-Forwarded-Proto"] == "http"
redirect_to protocol: "https://"
end
if Rails.configuration.maintenance_window.present?
unless cookies[:maintenance_window] == Rails.configuration.maintenance_window
flash.now[:maintenance] = I18n.t("maintenance.window_alert", date: Rails.configuration.maintenance_window)
end
end
# Sets the user domain variable
def set_user_domain
if Rails.env.test? || !Rails.configuration.loadbalanced_configuration
@user_domain = "greenlight"
else
@user_domain = parse_user_domain(request.host)
check_provider_exists
end
end
# Sets the appropriate locale.
def set_locale
update_locale(current_user)
# Sets the settinfs variable
def set_user_settings
@settings = Setting.find_or_create_by(provider: @user_domain)
end
# Show an information page when migration fails and there is a version error.
def migration_error?
render :migration_error, status: 500 unless ENV["DB_MIGRATE_FAILED"].blank?
end
def update_locale(user)
# Sets the appropriate locale.
def user_locale(user = current_user)
locale = if user && user.language != 'default'
user.language
else
@ -82,15 +92,43 @@ class ApplicationController < ActionController::Base
I18n.locale = locale.tr('-', '_') unless locale.nil?
end
def meeting_name_limit
MEETING_NAME_LIMIT
# Checks to make sure that the admin has changed his password from the default
def check_admin_password
if current_user&.has_role?(:admin) && current_user.email == "admin@example.com" &&
current_user&.greenlight_account? && current_user&.authenticate(Rails.configuration.admin_password_default)
flash.now[:alert] = I18n.t("default_admin",
edit_link: edit_user_path(user_uid: current_user.uid) + "?setting=password").html_safe
end
end
helper_method :meeting_name_limit
def user_name_limit
USER_NAME_LIMIT
# Checks if the user is banned and logs him out if he is
def check_user_role
if current_user&.has_role? :denied
session.delete(:user_id)
redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") }
elsif current_user&.has_role? :pending
session.delete(:user_id)
redirect_to root_path, flash: { alert: I18n.t("registration.approval.fail") }
end
end
# Redirects the user to a Maintenance page if turned on
def maintenance_mode?
if ENV["MAINTENANCE_MODE"] == "true"
render "errors/greenlight_error", status: 503, formats: :html,
locals: {
status_code: 503,
message: I18n.t("errors.maintenance.message"),
help: I18n.t("errors.maintenance.help"),
}
end
if Rails.configuration.maintenance_window.present?
unless cookies[:maintenance_window] == Rails.configuration.maintenance_window
flash.now[:maintenance] = I18n.t("maintenance.window_alert", date: Rails.configuration.maintenance_window)
end
end
end
helper_method :user_name_limit
# Relative root helper (when deploying to subdirectory).
def relative_root
@ -105,85 +143,60 @@ class ApplicationController < ActionController::Base
end
helper_method :bigbluebutton_endpoint_default?
def recording_thumbnails?
Rails.configuration.recording_thumbnails
end
helper_method :recording_thumbnails?
def allow_greenlight_users?
allow_greenlight_accounts?
end
helper_method :allow_greenlight_users?
# Determines if a form field needs the is-invalid class.
def form_is_invalid?(obj, key)
'is-invalid' unless obj.errors.messages[key].empty?
end
helper_method :form_is_invalid?
# Default, unconfigured meeting options.
def default_meeting_options
invite_msg = I18n.t("invite_message")
{
user_is_moderator: false,
meeting_logout_url: request.base_url + logout_room_path(@room),
meeting_recorded: true,
moderator_message: "#{invite_msg}\n\n#{request.base_url + room_path(@room)}",
host: request.host,
recording_default_visibility: Setting.find_or_create_by!(provider: user_settings_provider)
.get_value("Default Recording Visibility") == "public"
}
end
# Manually deal with 401 errors
rescue_from CanCan::AccessDenied do |_exception|
render "errors/greenlight_error"
def allow_greenlight_accounts?
return Rails.configuration.allow_user_signup unless Rails.configuration.loadbalanced_configuration
return false unless @user_domain && !@user_domain.empty? && Rails.configuration.allow_user_signup
return false if @user_domain == "greenlight"
# Proceed with retrieving the provider info
begin
provider_info = retrieve_provider_info(@user_domain, 'api2', 'getUserGreenlightCredentials')
provider_info['provider'] == 'greenlight'
rescue => e
logger.error "Error in checking if greenlight accounts are allowed: #{e}"
false
end
end
helper_method :allow_greenlight_accounts?
# Checks to make sure that the admin has changed his password from the default
def check_admin_password
if current_user&.has_role?(:admin) && current_user.email == "admin@example.com" &&
current_user&.greenlight_account? && current_user&.authenticate(Rails.configuration.admin_password_default)
flash.now[:alert] = I18n.t("default_admin",
edit_link: edit_user_path(user_uid: current_user.uid) + "?setting=password").html_safe
end
# Determine if Greenlight is configured to allow user signups.
def allow_user_signup?
Rails.configuration.allow_user_signup
end
helper_method :allow_user_signup?
def redirect_to_https
if Rails.configuration.loadbalanced_configuration && request.headers["X-Forwarded-Proto"] == "http"
redirect_to protocol: "https://"
# Gets all configured omniauth providers.
def configured_providers
Rails.configuration.providers.select do |provider|
Rails.configuration.send("omniauth_#{provider}")
end
end
helper_method :configured_providers
def set_user_domain
if Rails.env.test? || !Rails.configuration.loadbalanced_configuration
@user_domain = "greenlight"
else
@user_domain = parse_user_domain(request.host)
check_provider_exists
# Parses the url for the user domain
def parse_user_domain(hostname)
return hostname.split('.').first if Rails.configuration.url_host.empty?
Rails.configuration.url_host.split(',').each do |url_host|
return hostname.chomp(url_host).chomp('.') if hostname.include?(url_host)
end
''
end
helper_method :set_user_domain
# Checks if the user is banned and logs him out if he is
def check_user_role
if current_user&.has_role? :denied
session.delete(:user_id)
redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") }
elsif current_user&.has_role? :pending
session.delete(:user_id)
redirect_to root_path, flash: { alert: I18n.t("registration.approval.fail") }
end
# Include user domain in lograge logs
def append_info_to_payload(payload)
super
payload[:host] = @user_domain
end
helper_method :check_user_role
# Manually Handle BigBlueButton errors
def handle_bigbluebutton_error
render "errors/bigbluebutton_error"
end
# Manually deal with 401 errors
rescue_from CanCan::AccessDenied do |_exception|
render "errors/greenlight_error"
end
private
def check_provider_exists
@ -198,6 +211,7 @@ class ApplicationController < ActionController::Base
# Add a session variable if the provider exists
session[:provider_exists] = @user_domain
rescue => e
logger.error "Error in retrieve provider info: #{e}"
# Use the default site settings
@user_domain = "greenlight"

@ -16,15 +16,15 @@
# 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 SessionsHelper
module Authenticator
extend ActiveSupport::Concern
# Logs a user into GreenLight.
def login(user)
migrate_twitter_user(user)
session[:user_id] = user.id
logger.info("Support: #{user.email} has successfully logged in.")
# If there are not terms, or the user has accepted them, check for email verification
if !Rails.configuration.terms || user.accepted_terms
check_email_verified(user)
@ -61,69 +61,9 @@ module SessionsHelper
session.delete(:user_id) if current_user
end
# Retrieves the current user.
def current_user
@current_user ||= User.where(id: session[:user_id]).includes(:roles).first
if Rails.configuration.loadbalanced_configuration
if @current_user && !@current_user.has_role?(:super_admin) &&
@current_user.provider != @user_domain
@current_user = nil
session.clear
end
end
@current_user
end
def generate_checksum(user_domain, redirect_url, secret)
string = user_domain + redirect_url + secret
OpenSSL::Digest.digest('sha1', string).unpack1("H*")
end
def parse_user_domain(hostname)
return hostname.split('.').first if Rails.configuration.url_host.empty?
Rails.configuration.url_host.split(',').each do |url_host|
return hostname.chomp(url_host).chomp('.') if hostname.include?(url_host)
end
''
end
def omniauth_options(env)
if env['omniauth.strategy'].options[:name] == "bn_launcher"
protocol = Rails.env.production? ? "https" : env["rack.url_scheme"]
customer_redirect_url = protocol + "://" + env["SERVER_NAME"] + ":" +
env["SERVER_PORT"]
user_domain = parse_user_domain(env["SERVER_NAME"])
env['omniauth.strategy'].options[:customer] = user_domain
env['omniauth.strategy'].options[:customer_redirect_url] = customer_redirect_url
env['omniauth.strategy'].options[:default_callback_url] = Rails.configuration.gl_callback_url
# This is only used in the old launcher and should eventually be removed
env['omniauth.strategy'].options[:checksum] = generate_checksum(user_domain, customer_redirect_url,
Rails.configuration.launcher_secret)
elsif env['omniauth.strategy'].options[:name] == "google"
set_hd(env, ENV['GOOGLE_OAUTH2_HD'])
elsif env['omniauth.strategy'].options[:name] == "office365"
set_hd(env, ENV['OFFICE365_HD'])
end
end
def set_hd(env, hd)
if hd
hd_opts = hd.split(',')
env['omniauth.strategy'].options[:hd] =
if hd_opts.empty?
nil
elsif hd_opts.length == 1
hd_opts[0]
else
hd_opts
end
end
end
private
# Migrates all of the twitter users rooms to the new account
def migrate_twitter_user(user)
if !session["old_twitter_user_id"].nil? && user.provider != "twitter"
old_user = User.find(session["old_twitter_user_id"])

@ -0,0 +1,109 @@
# 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 'bigbluebutton_api'
module BbbServer
extend ActiveSupport::Concern
include BbbApi
META_LISTED = "gl-listed"
# Checks if a room is running on the BigBlueButton server.
def room_running?(bbb_id)
bbb_server.is_meeting_running?(bbb_id)
end
def get_recordings(meeting_id)
bbb_server.get_recordings(meetingID: meeting_id)
end
def get_multiple_recordings(meeting_ids)
bbb_server.get_recordings(meetingID: meeting_ids)
end
# Returns a URL to join a user into a meeting.
def join_path(room, name, options = {}, uid = nil)
# Create the meeting, even if it's running
start_session(room, options)
# Determine the password to use when joining.
password = options[:user_is_moderator] ? room.moderator_pw : room.attendee_pw
# Generate the join URL.
join_opts = {}
join_opts[:userID] = uid if uid
join_opts[:join_via_html5] = true
join_opts[:guest] = true if options[:require_moderator_approval] && !options[:user_is_moderator]
bbb_server.join_meeting_url(room.bbb_id, name, password, join_opts)
end
# Creates a meeting on the BigBlueButton server.
def start_session(room, options = {})
create_options = {
record: options[:meeting_recorded].to_s,
logoutURL: options[:meeting_logout_url] || '',
moderatorPW: room.moderator_pw,
attendeePW: room.attendee_pw,
moderatorOnlyMessage: options[:moderator_message],
muteOnStart: options[:mute_on_start] || false,
"meta_#{META_LISTED}": options[:recording_default_visibility] || false,
"meta_bbb-origin-version": Greenlight::Application::VERSION,
"meta_bbb-origin": "Greenlight",
"meta_bbb-origin-server-name": options[:host]
}
create_options[:guestPolicy] = "ASK_MODERATOR" if options[:require_moderator_approval]
# Send the create request.
begin
meeting = bbb_server.create_meeting(room.name, room.bbb_id, create_options)
# Update session info.
unless meeting[:messageKey] == 'duplicateWarning'
room.update_attributes(sessions: room.sessions + 1,
last_session: DateTime.now)
end
rescue BigBlueButton::BigBlueButtonException => e
puts "BigBlueButton failed on create: #{e.key}: #{e.message}"
raise e
end
end
# Gets the number of recordings for this room
def recording_count(bbb_id)
bbb_server.get_recordings(meetingID: bbb_id)[:recordings].length
end
# Update a recording from a room
def update_recording(record_id, meta)
meta[:recordID] = record_id
bbb_server.send_api_request("updateRecordings", meta)
end
# Deletes a recording from a room.
def delete_recording(record_id)
bbb_server.delete_recordings(record_id)
end
# Deletes all recordings associated with the room.
def delete_all_recordings(bbb_id)
record_ids = bbb_server.get_recordings(meetingID: bbb_id)[:recordings].pluck(:recordID)
bbb_server.delete_recordings(record_ids) unless record_ids.empty?
end
end

@ -21,69 +21,110 @@ module Emailer
# Sends account activation email.
def send_activation_email(user)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
@user = user
UserMailer.verify_email(@user, user_verification_link, logo_image, user_color).deliver
UserMailer.verify_email(user, user_verification_link(user), @settings).deliver
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
end
# Sends password reset email.
def send_password_reset_email(user)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
@user = user
UserMailer.password_reset(@user, reset_link, logo_image, user_color).deliver_now
UserMailer.password_reset(user, reset_link(user), @settings).deliver_now
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent", email_type: t("reset_password.subtitle"))
end
end
def send_user_promoted_email(user, role)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
UserMailer.user_promoted(user, role, root_url, logo_image, user_color).deliver_now
UserMailer.user_promoted(user, role, root_url, @settings).deliver_now
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
end
end
def send_user_demoted_email(user, role)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
UserMailer.user_demoted(user, role, root_url, logo_image, user_color).deliver_now
UserMailer.user_demoted(user, role, root_url, @settings).deliver_now
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
end
end
# Sends inivitation to join
def send_invitation_email(name, email, token)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
@token = token
UserMailer.invite_email(name, email, invitation_link, logo_image, user_color).deliver_now
UserMailer.invite_email(name, email, invitation_link(token), @settings).deliver_now
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("administrator.flash.invite", email: email)
end
end
def send_user_approved_email(user)
return unless Rails.configuration.enable_email_verification
begin
return unless Rails.configuration.enable_email_verification
UserMailer.approve_user(user, root_url, logo_image, user_color).deliver_now
UserMailer.approve_user(user, root_url, @settings).deliver_now
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
end
def send_approval_user_signup_email(user)
return unless Rails.configuration.enable_email_verification
admin_emails = admin_emails()
unless admin_emails.empty?
UserMailer.approval_user_signup(user, admins_url, logo_image, user_color, admin_emails).deliver_now
begin
return unless Rails.configuration.enable_email_verification
admin_emails = admin_emails()
UserMailer.approval_user_signup(user, admins_url, admin_emails, @settings).deliver_now unless admin_emails.empty?
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
end
end
def send_invite_user_signup_email(user)
return unless Rails.configuration.enable_email_verification
admin_emails = admin_emails()
unless admin_emails.empty?
UserMailer.invite_user_signup(user, admins_url, logo_image, user_color, admin_emails).deliver_now
begin
return unless Rails.configuration.enable_email_verification
admin_emails = admin_emails()
UserMailer.invite_user_signup(user, admins_url, admin_emails, @settings).deliver_now unless admin_emails.empty?
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
end
end
private
# Returns the link the user needs to click to verify their account
def user_verification_link
edit_account_activation_url(token: @user.activation_token, email: @user.email)
def user_verification_link(user)
edit_account_activation_url(token: user.activation_token, email: user.email)
end
def admin_emails
@ -91,21 +132,21 @@ module Emailer
if Rails.configuration.loadbalanced_configuration
admins = admins.without_role(:super_admin)
.where(provider: user_settings_provider)
.where(provider: @user_domain)
end
admins.collect(&:email).join(",")
end
def reset_link
edit_password_reset_url(@user.reset_token, email: @user.email)
def reset_link(user)
edit_password_reset_url(user.reset_token, email: user.email)
end
def invitation_link
if allow_greenlight_users?
signup_url(invite_token: @token)
def invitation_link(token)
if allow_greenlight_accounts?
signup_url(invite_token: token)
else
root_url(invite_token: @token)
root_url(invite_token: token)
end
end
end

@ -18,29 +18,29 @@
module Recorder
extend ActiveSupport::Concern
include ::BbbApi
include RecordingsHelper
# Fetches all recordings for a room.
def recordings(room_bbb_id, provider, search_params = {}, ret_search_params = false)
res = bbb(provider).get_recordings(meetingID: room_bbb_id)
def recordings(room_bbb_id, search_params = {}, ret_search_params = false)
res = get_recordings(room_bbb_id)
format_recordings(res, search_params, ret_search_params)
end
# Fetches a rooms public recordings.
def public_recordings(room_bbb_id, provider, search_params = {}, ret_search_params = false)
search, order_col, order_dir, recs = recordings(room_bbb_id, provider, search_params, ret_search_params)
def public_recordings(room_bbb_id, search_params = {}, ret_search_params = false)
search, order_col, order_dir, recs = recordings(room_bbb_id, search_params, ret_search_params)
[search, order_col, order_dir, recs.select { |r| r[:metadata][:"gl-listed"] == "true" }]
end
# Makes paginated API calls to get recordings
def all_recordings(room_bbb_ids, provider, search_params = {}, ret_search_params = false, search_name = false)
def all_recordings(room_bbb_ids, search_params = {}, ret_search_params = false, search_name = false)
res = { recordings: [] }
until room_bbb_ids.empty?
# bbb.get_recordings returns an object
# take only the array portion of the object that is returned
full_res = bbb(provider).get_recordings(meetingID: room_bbb_ids.pop(Rails.configuration.pagination_number))
full_res = get_multiple_recordings(room_bbb_ids.pop(Rails.configuration.pagination_number))
res[:recordings].push(*full_res[:recordings])
end

@ -19,20 +19,12 @@
module Registrar
extend ActiveSupport::Concern
def registration_method
Setting.find_or_create_by!(provider: user_settings_provider).get_value("Registration Method")
end
def open_registration
registration_method == Rails.configuration.registration_methods[:open]
end
def approval_registration
registration_method == Rails.configuration.registration_methods[:approval]
@settings.get_value("Registration Method") == Rails.configuration.registration_methods[:approval]
end
def invite_registration
registration_method == Rails.configuration.registration_methods[:invite]
@settings.get_value("Registration Method") == Rails.configuration.registration_methods[:invite]
end
# Returns a hash containing whether the user has been invited and if they

@ -0,0 +1,161 @@
# 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 Rolify
extend ActiveSupport::Concern
# Gets all roles
def all_roles(selected_role)
@roles = Role.editable_roles(@user_domain)
if @roles.count.zero?
Role.create_default_roles(@user_domain)
@roles = Role.editable_roles(@user_domain)
end
@selected_role = if selected_role.nil?
@roles.find_by(name: 'user')
else
@roles.find(selected_role)
end
@roles
end
# Creates a new role
def create_role(new_role_name)
# Make sure that the role name isn't a duplicate or a reserved name like super_admin or empty
return nil if Role.duplicate_name(new_role_name, @user_domain) || new_role_name.strip.empty?
Role.create_new_role(new_role_name, @user_domain)
end
# Updates a user's roles
def update_roles(roles)
# Check that the user can manage users
return true unless current_user.highest_priority_role.can_manage_users
new_roles = roles.split(' ').map(&:to_i)
old_roles = @user.roles.pluck(:id)
added_role_ids = new_roles - old_roles
removed_role_ids = old_roles - new_roles
added_roles = []
removed_roles = []
current_user_role = current_user.highest_priority_role
# Check that the user has the permissions to add all the new roles
added_role_ids.each do |id|
role = Role.find(id)
# Admins are able to add the admin role to other users. All other roles may only
# add roles with a higher priority
if (role.priority > current_user_role.priority || current_user_role.name == "admin") &&
role.provider == @user_domain
added_roles << role
else
return false
end
end
# Check that the user has the permissions to remove all the deleted roles
removed_role_ids.each do |id|
role = Role.find(id)
# Admins are able to remove the admin role from other users. All other roles may only
# remove roles with a higher priority
if (role.priority > current_user_role.priority || current_user_role.name == "admin") &&
role.provider == @user_domain
removed_roles << role
else
return false
end
end
# Send promoted/demoted emails
added_roles.each { |role| send_user_promoted_email(@user, role) if role.send_promoted_email }
removed_roles.each { |role| send_user_demoted_email(@user, role) if role.send_demoted_email }
# Update the roles
@user.roles.delete(removed_roles)
@user.roles << added_roles
# Make sure each user always has at least the user role
@user.roles = [Role.find_by(name: "user", provider: @user_domain)] if @user.roles.count.zero?
@user.save!
end
# Updates a roles priority
def update_priority(role_to_update)
user_role = Role.find_by(name: "user", provider: @user_domain)
admin_role = Role.find_by(name: "admin", provider: @user_domain)
current_user_role = current_user.highest_priority_role
# Users aren't allowed to update the priority of the admin or user roles
return false if role_to_update.include?(user_role.id.to_s) || role_to_update.include?(admin_role.id.to_s)
# Restrict users to only updating the priority for roles in their domain with a higher
# priority
role_to_update.each do |id|
role = Role.find(id)
return false if role.priority <= current_user_role.priority || role.provider != @user_domain
end
# Update the roles priority including the user role
top_priority = 0
role_to_update.each_with_index do |id, index|
new_priority = index + [current_user_role.priority, 0].max + 1
top_priority = new_priority
Role.where(id: id).update_all(priority: new_priority)
end
user_role.priority = top_priority + 1
user_role.save!
end
# Update Permissions
def update_permissions(role)
current_user_role = current_user.highest_priority_role
# Checks that it is valid for the provider to update the role
return false if role.priority <= current_user_role.priority || role.provider != @user_domain
role_params = params.require(:role).permit(:name)
permission_params = params.require(:role).permit(:can_create_rooms, :send_promoted_email,
:send_demoted_email, :can_edit_site_settings, :can_edit_roles, :can_manage_users, :colour)
# Role is a default role so users can't change the name
role_params[:name] = role.name if Role::RESERVED_ROLE_NAMES.include?(role.name)
# Make sure if the user is updating the role name that the role name is valid
if role.name != role_params[:name] && !Role.duplicate_name(role_params[:name], @user_domain) &&
!role_params[:name].strip.empty?
role.name = role_params[:name]
elsif role.name != role_params[:name]
return false
end
role.update(permission_params)
role.save!