require 'current_user' require 'canonical_url' require_dependency 'discourse' require_dependency 'custom_renderer' require 'archetype' require_dependency 'rate_limiter' class ApplicationController < ActionController::Base include CurrentUser include CanonicalURL::ControllerExtensions serialization_scope :guardian protect_from_forgery before_filter :inject_preview_style before_filter :block_if_maintenance_mode before_filter :check_restricted_access before_filter :authorize_mini_profiler before_filter :store_incoming_links before_filter :preload_json before_filter :check_xhr rescue_from Exception do |exception| unless [ ActiveRecord::RecordNotFound, ActionController::RoutingError, ActionController::UnknownController, AbstractController::ActionNotFound].include? exception.class begin ErrorLog.report_async!(exception, self, request, current_user) rescue # dont care give up end end raise end # Some exceptions class RenderEmpty < Exception; end class NotLoggedIn < Exception; end # Render nothing unless we are an xhr request rescue_from RenderEmpty do render 'default/empty' end # If they hit the rate limiter rescue_from RateLimiter::LimitExceeded do |e| time_left = "" if e.available_in < 1.minute.to_i time_left = I18n.t("rate_limiter.seconds", count: e.available_in) elsif e.available_in < 1.hour.to_i time_left = I18n.t("rate_limiter.minutes", count: (e.available_in / 1.minute.to_i)) else time_left = I18n.t("rate_limiter.hours", count: (e.available_in / 1.hour.to_i)) end render json: {errors: [I18n.t("rate_limiter.too_many_requests", time_left: time_left)]}, status: 429 end rescue_from Discourse::NotLoggedIn do |e| raise e if Rails.env.test? redirect_to root_path end rescue_from Discourse::NotFound do if request.format.html? # for now do a simple remap, we may look at cleaner ways of doing the render raise ActiveRecord::RecordNotFound else render file: 'public/404', formats: [:html], layout: false, status: 404 end end rescue_from Discourse::InvalidAccess do render file: 'public/403', formats: [:html], layout: false, status: 403 end def store_preloaded(key, json) @preloaded ||= {} # I dislike that there is a gsub as opposed to a gsub! # but we can not be mucking with user input, I wonder if there is a way # to inject this safty deeper in the library or even in AM serializer @preloaded[key] = json.gsub(" request.fullpath) return false end end def mini_profiler_enabled? defined?(Rack::MiniProfiler) and current_user.try(:admin?) end def authorize_mini_profiler return unless mini_profiler_enabled? Rack::MiniProfiler.authorize_request end def requires_parameters(*required) required.each do |p| raise Discourse::InvalidParameters.new(p) unless params.has_key?(p) end end alias :requires_parameter :requires_parameters def store_incoming_links if request.referer.present? parsed = URI.parse(request.referer) if parsed.host != request.host IncomingLink.create(url: request.url, referer: request.referer[0..999]) end end end def check_xhr unless (controller_name == 'forums' || controller_name == 'user_open_ids') # render 'default/empty' unless ((request.format && request.format.json?) or request.xhr?) raise RenderEmpty.new unless ((request.format && request.format.json?) or request.xhr?) end end def ensure_logged_in raise Discourse::NotLoggedIn.new unless current_user.present? end end