148 lines
4.3 KiB
Ruby
148 lines
4.3 KiB
Ruby
# TODO : Delete this and associated spec once 'api/widget/config' end point is merged
|
|
class WidgetsController < ActionController::Base
|
|
include WidgetHelper
|
|
|
|
before_action :set_global_config
|
|
before_action :set_web_widget
|
|
before_action :ensure_account_is_active
|
|
before_action :ensure_location_is_supported
|
|
before_action :validate_origin_domain
|
|
before_action :set_token
|
|
before_action :set_contact
|
|
before_action :build_contact
|
|
after_action :allow_iframe_requests
|
|
|
|
private
|
|
|
|
def set_global_config
|
|
@global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL', 'DIRECT_UPLOADS_ENABLED')
|
|
end
|
|
|
|
def set_web_widget
|
|
@web_widget = ::Channel::WebWidget.find_by!(website_token: permitted_params[:website_token])
|
|
rescue ActiveRecord::RecordNotFound
|
|
Rails.logger.error('web widget does not exist')
|
|
render json: { error: 'web widget does not exist' }, status: :not_found
|
|
end
|
|
|
|
def validate_origin_domain
|
|
# Only validate origin if website_url is configured
|
|
return if @web_widget.website_url.blank?
|
|
|
|
origin_domain = extract_domain_from_origin
|
|
return if domain_allowed?(origin_domain, @web_widget.website_url)
|
|
|
|
Rails.logger.warn('Widget access denied.')
|
|
render json: { error: 'Widget access denied.' }, status: :forbidden
|
|
end
|
|
|
|
def domain_allowed?(origin_domain, website_url)
|
|
return false if origin_domain.blank?
|
|
|
|
# Split website_url by comma to handle multiple domains/wildcards
|
|
allowed_domains = website_url.split(',').map(&:strip).reject(&:blank?)
|
|
|
|
allowed_domains.any? do |allowed_domain|
|
|
# Extract domain and protocol from the allowed domain
|
|
allowed_domain_without_protocol = extract_domain_from_url(allowed_domain)
|
|
allowed_protocol = extract_protocol_from_url(allowed_domain)
|
|
origin_protocol = extract_protocol_from_origin
|
|
|
|
# Check if the extracted domain starts with wildcard
|
|
if allowed_domain_without_protocol&.start_with?('*.')
|
|
# Handle wildcard domains (e.g., "*.example.com")
|
|
wildcard_suffix = allowed_domain_without_protocol[2..-1] # Remove "*.", keep "example.com"
|
|
origin_domain.end_with?(wildcard_suffix) && origin_protocol == allowed_protocol
|
|
else
|
|
# Handle exact domain and protocol match
|
|
origin_domain == allowed_domain_without_protocol && origin_protocol == allowed_protocol
|
|
end
|
|
end
|
|
end
|
|
|
|
def extract_domain_from_origin
|
|
origin = request.headers['Origin']
|
|
return nil if origin.blank?
|
|
|
|
extract_domain_from_url(origin)
|
|
end
|
|
|
|
def extract_protocol_from_origin
|
|
origin = request.headers['Origin']
|
|
return nil if origin.blank?
|
|
|
|
extract_protocol_from_url(origin)
|
|
end
|
|
|
|
def extract_domain_from_url(url)
|
|
return nil if url.blank?
|
|
|
|
# Parse the URL and extract the domain
|
|
uri = URI.parse(url)
|
|
uri.host&.downcase
|
|
rescue URI::InvalidURIError
|
|
nil
|
|
end
|
|
|
|
def extract_protocol_from_url(url)
|
|
return nil if url.blank?
|
|
|
|
# Parse the URL and extract the protocol
|
|
uri = URI.parse(url)
|
|
uri.scheme&.downcase
|
|
rescue URI::InvalidURIError
|
|
nil
|
|
end
|
|
|
|
def set_token
|
|
@token = permitted_params[:cw_conversation]
|
|
@auth_token_params = if @token.present?
|
|
::Widget::TokenService.new(token: @token).decode_token
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
|
|
def set_contact
|
|
return if @auth_token_params[:source_id].nil?
|
|
|
|
@contact_inbox = ::ContactInbox.find_by(
|
|
inbox_id: @web_widget.inbox.id,
|
|
source_id: @auth_token_params[:source_id]
|
|
)
|
|
|
|
@contact = @contact_inbox&.contact
|
|
end
|
|
|
|
def build_contact
|
|
return if @contact.present?
|
|
|
|
@contact_inbox, @token = build_contact_inbox_with_token(@web_widget, additional_attributes)
|
|
@contact = @contact_inbox.contact
|
|
end
|
|
|
|
def ensure_account_is_active
|
|
render json: { error: 'Account is suspended' }, status: :unauthorized unless @web_widget.inbox.account.active?
|
|
end
|
|
|
|
def ensure_location_is_supported; end
|
|
|
|
def additional_attributes
|
|
if @web_widget.inbox.account.feature_enabled?('ip_lookup')
|
|
{ created_at_ip: request.remote_ip }
|
|
else
|
|
{}
|
|
end
|
|
end
|
|
|
|
def permitted_params
|
|
params.permit(:website_token, :cw_conversation)
|
|
end
|
|
|
|
def allow_iframe_requests
|
|
response.headers.delete('X-Frame-Options')
|
|
end
|
|
end
|
|
|
|
WidgetsController.prepend_mod_with('WidgetsController')
|