Bot spamming with invalid utf-8 characters - ruby-on-rails

Our rails app is being slammed by a random spamming bot and they are trying to post some weird stuff.
I already tried different solutions:
The gem invalid_utf8_rejector
The gem rack-uri_sanitizer
Some custom code in our application_controller.rb file in a
before_filter method. before_filter :force_utf8_params
def force_utf8_params
traverse = lambda do |object, block|
if object.kind_of?(Hash)
object.each_value { |o| traverse.call(o, block) }
elsif object.kind_of?(Array)
object.each { |o| traverse.call(o, block) }
else
block.call(object)
end
object
end
force_encoding = lambda do |o|
return redirect_to #MYAPP_URL+"/not-found" if o.is_a?(String) && !o.valid_encoding?
end
traverse.call(params, force_encoding)
end
Here is the error we are getting: invalid byte sequence in UTF-8
I don't know what else to do.

you need to change your code a bit, the original solution for this problem uses lamda, which is appropriate, since it tries to force encode or strip some characters. But you need to redirect and proceed with execution, so you need to use proc.
force_encoding = proc do |o|
redirect_to #MYAPP_URL+"/not-found" and return if o.is_a?(String) && !o.valid_encoding?
end

Related

How to DRY a list of functions in ruby that are differ only by a single line of code?

I have a User model in a ROR application that has multiple methods like this
#getClient() returns an object that knows how to find certain info for a date
#processHeaders() is a function that processes output and updates some values in the database
#refreshToken() is function that is called when an error occurs when requesting data from the object returned by getClient()
def transactions_on_date(date)
if blocked?
# do something
else
begin
output = getClient().transactions(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().transactions(date)
process_fitbit_rate_headers(output)
return output
end
end
end
def events_on_date(date)
if blocked?
# do something
else
begin
output = getClient().events(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().events(date)
processHeaders(output)
return output
end
end
end
I have several functions in my User class that look exactly the same. The only difference among these functions is the line output = getClient().something(date). Is there a way that I can make this code look cleaner so that I do not have a repetitive list of functions.
The answer is usually passing in a block and doing it functional style:
def handle_blocking(date)
if blocked?
# do something
else
begin
output = yield(date)
processHeaders(output)
output
rescue UnauthorizedError => ex
refresh_token
output = yield(date)
process_fitbit_rate_headers(output)
output
end
end
end
Then you call it this way:
handle_blocking(date) do |date|
getClient.something(date)
end
That allows a lot of customization. The yield call executes the block of code you've supplied and passes in the date argument to it.
The process of DRYing up your code often involves looking for patterns and boiling them down to useful methods like this. Using a functional approach can keep things clean.
Yes, you can use Object#send: getClient().send(:method_name, date).
BTW, getClient is not a proper Ruby method name. It should be get_client.
How about a combination of both answers:
class User
def method_missing sym, *args
m_name = sym.to_s
if m_name.end_with? '_on_date'
prop = m_name.split('_').first.to_sym
handle_blocking(args.first) { getClient().send(prop, args.first) }
else
super(sym, *args)
end
end
def respond_to? sym, private=false
m_name.end_with?('_on_date') || super(sym, private)
end
def handle_blocking date
# see other answer
end
end
Then you can call "transaction_on_date", "events_on_date", "foo_on_date" and it would work.

rails get output from controller methods?

I have the following code in my Application Controller
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def get_mkts(all_idx)
mkts = Set.new
all_idx.each do |idx|
m = decode_index_names(idx)
puts m[:mkt]
mkts.add(m[:mkt])
end
end
def decode_index_names(name)
mkt = name.split(/[0-9]/)[0]
type = get_first_num(mkt);
{:mkt => mkt,:type => type}
end
def get_first_num(str)
str[/\d+/]
end
end
And I'm inputting an array of strings like this:
["USEQUITIES2tv10", "USEQUITIES2tv15", "USEQUITIES2tv20", "NONUSEQUITIES2tv5", "NONUSEQUITIES2tv10", "NONUSEQUITIES2tv15", "NONUSEQUITIES2tv20", "BONDS2tv5", "BONDS2tv10", "BONDS2tv15", "BONDS2tv20"
, "ES1", "ES2tv5", "ES2tv10", "ES2tv15", "ES2tv20", "NQ1", "NQ2tv5", "NQ2tv10", "NQ2tv15", "USBONDS2tv5", "USBONDS2tv10", "USBONDS2tv15", "USBONDS2tv20", "GERMANBONDS2tv5", "GERMANBONDS2tv10", "GERMANB
ONDS2tv15", "GERMANBONDS2tv20", "EQUITIESnBONDS2tv5", "EQUITIESnBONDS2tv10", "EQUITIESnBONDS2tv15", "EQUITIESnBONDS2tv20", "COMMODITIES2tv5", "COMMODITIES2tv10", "COMMODITIES2tv15", "COMMODITIES2tv20",
"CURRENCIES2tv5"]
The method get_mkts is supposed to loop through, extract the text up tot the first number and create a unique array of symbols (which is why i used Set). However, I can't get the method to output anything other than the original input. In rails console I'm able to see from the output of "puts m[:mkt]" that each loop through is getting the correct value, I just don't know how to return the set mkts instead of the input value. Any ideas?
Ruby methods return the result of the last statement if you don't use return. In your case it's each and that's why you get the input back. You can do something like this:
def get_mkts(all_idx)
mkts = Set.new
all_idx.each do |idx|
m = decode_index_names(idx)
puts m[:mkt]
mkts.add(m[:mkt])
end
mkts
end
This will return the mkts set instead of all_idx.
The method can be rewritten has:
def get_mkts(all_idx)
all_idx.map { |idx| decode_index_names(idx) }.uniq
end
Looks more rubyish and its shorter and cleaner

Rails - 'can't dump hash with default proc' during custom validation

I have 2 models. User and Want. A User has_many: Wants.
The Want model has a single property besides user_id, that's name.
I have written a custom validation in the Want model so that a user cannot submit to create 2 wants with the same name:
validate :existing_want
private
def existing_want
return unless errors.blank?
errors.add(:existing_want, "you already want that") if user.already_wants? name
end
The already_wants? method is in the User model:
def already_wants? want_name
does_want_already = false
self.wants.each { |w| does_want_already = true if w.name == want_name }
does_want_already
end
The validation specs pass in my model tests, but my feature tests fail when i try and submit a duplicate to the create action in the WantsController:
def create
#want = current_user.wants.build(params[:want])
if #want.save
flash[:success] = "success!"
redirect_to user_account_path current_user.username
else
flash[:validation] = #want.errors
redirect_to user_account_path current_user.username
end
end
The error I get: can't dump hash with default proc
No stack trace that leads to my code.
I have narrowed the issue down to this line:
self.wants.each { |w| does_want_already = true if w.name == want_name }
if I just return true regardless the error shows in my view as I would like.
I don't understand? What's wrong? and why is it so cryptic?
Thanks.
Without a stack trace (does it lead anywhere, or does it just not appear?) it is difficult to know what exactly is happening, but here's how you can reproduce this error in a clean environment:
# initialize a new hash using a block, so it has a default proc
h = Hash.new {|h,k| h[k] = k }
# attempt to serialize it:
Marshal.dump(h)
#=> TypeError: can't dump hash with default proc
Ruby can't serialize procs, so it wouldn't be able to properly reconstitute that serialized hash, hence the error.
If you're reasonably sure that line is the source of your trouble, try refactoring it to see if that solves the problem.
def already_wants? want_name
wants.any? {|want| want_name == want.name }
end
or
def already_wants? want_name
wants.where(name: want_name).count > 0
end

Is there a more ruby way of doing this

Ok so i have this helper
def current_company_title
(Company.find_by_id(params["company_id"]).name rescue nil) || (#companies.first.name rescue nil) current_user.company.name
end
Basically what I am achieving with this is the following ...
If the param["company_id"] exists then try to get the company and if not then
if #companies exists grab the first company name and if not then get the current users company name
This works but the rescues seem like a hack...any idea on another way to achieve this
Indeed rescue is kind of a hack, id' probably split it up into two methods and then use try to fetch the name if available: http://api.rubyonrails.org/classes/Object.html#method-i-try
def current_company
#current_company ||= Company.find_by_id(params[:company_id]) || #companies.try(:first) || current_user.try(:company)
end
def current_company_name
current_company.try(:name)
end
Company.find_by_id(params["company_id"]).name`
find and its derivates are meant to be used when you're sure-ish you'll have a positive result, and only in some cases (row was deleted, etc) errors. That's why it raises an exception. In your case, you're assuming it's gonna fail, so a regular where, which would return nil if no rows was found, would do better, and remove the first rescue
#companies.first.name rescue nil
could be replaced by
#companies.first.try(:name)
I'll let you check the api for more on the topic of try. It's not regular ruby, it's a Rails addition.
Less "magic", simple code, simple to read:
def current_company_title
company = Company.where(id: params["company_id"]).presence
company ||= #companies.try(:first)
company ||= current_user.company
company.name
end
Ps. Not a big fan of Rails' try method, but it solves the problem.
def current_company_title
if params["company_id"]
return Company.find_by_id(params["company_id"]).name
elsif #companies
return #companies.first.name
else
return current_user.company.name
end
end
The rescues are a hack, and will obscure other errors if they occur.
Try this:
(Company.find_by_id(params["company_id"].name if Company.exists?(params["company_id"]) ||
(#companies.first.name if #companies && #companies.first) ||
current_user.company.name
then you can extract each of the bracketed conditions to their own methods to make it more readable, and easier to tweak the conditions:
company_name_from_id(params["company_id"]) || name_from_first_in_collection(#companies) || current_user_company_name
def company_name_from_id(company_id)
company=Company.find_by_id(company_id)
company.name if company
end
def name_from_first_in_collection(companies)
companies.first.name if companies && companies.first
end
def current_user_company_name
current_user.company.name if current_user.company
end
[Company.find_by_id(params["company_id"]),
#companies.to_a.first,
current_user.company
].compact.first.name

find untranslated locales in rails

I'm using rails 2.3.5 with i18n. I's there a way to find all not yet translated locales in all views?
Maybe a after_filter in the application controller, but which code I can use for this job?
thanks
When using the i18n gem (which Rails does), you can specify your own exception handler. Try this code:
# A simple exception handler that behaves like the default exception handler
# but additionally logs missing translations to a given log.
#
module I18n
class << self
def missing_translations_logger
##missing_translations_logger ||= Logger.new("#{RAILS_ROOT}/log/missing_translations.log")
end
def missing_translations_log_handler(exception, locale, key, options)
if MissingTranslationData === exception # use MissingTranslation in Rails 3.x !!!
puts "logging #{exception.message}"
missing_translations_logger.warn(exception.message)
return exception.message
else
raise exception
end
end
end
end
I18n.exception_handler = :missing_translations_log_handler
(put it for example into RAILS_ROOT/config/initializers/i18n.rb)
Now, whenever you try to translate a key for which you have no translation specified, a warning gets printed into RAILS_ROOT/log/missing_translations.log.
Hope this helps!
I couldn't find a simple trick to do this, so I did this. First implement a 'before_filter' in your application_controller.rb
before_filter :set_user_language
# set the language, 'zen' is a special URL parameter that makes localizations the use the 't' method visible
def set_user_language
# turn on 'zen' to see localization by adding 'zen=true' to query string, will stay on until a query with 'zen=false'
session[:zen] = (session[:zen] || params[:zen] == "true") && params[:zen] != "false"
I18n.locale = 'en'
end
The above finds 'zen=true' and 'zen=false' in the query string. Then add this method to your application_helper.rb:
def t(*args)
result = super(*args)
result = "[#{result}]" if session[:zen] && result.is_a?(String)
result
end
With this method 'zen=true' makes the 't' method display localized strings in square brackets []. To turn it off enter a query string with 'zen=false'.

Resources