class PeriscopeController < ActionController::Base before_filter :authenticate protect_from_forgery :except => [:look, :login] def look if !params[:sql].nil? render :json => run_sql(params[:sql]) else render :json => {:error => "Command not understood"} end end def login render :json => get_info() end private def authenticate unless PeriscopeRails::Config.check_password(params[:password].to_s) render :json => {:error => "Password invalid."} end end def run_sql(sql_command) #TODO: protect based on CFG, not blacklist bad_words = %W{drop delete update into insert index add remove grant revoke create createdb} bad_words += %W{createuser createrole destroy disconnect exec execute dropdb primary key rollback ; --} rows = nil error_message = nil command = sql_command.to_s.strip command_words = command.downcase.gsub(/[^a-zA-Z0-9]/, " ").gsub(/\s+/, " ").split(" ") if command == "" #nothing elsif (command_words & bad_words).size > 0 error_message = "Potentially harmful keyword found, blocking script." else begin ActiveRecord::Base.transaction do rows = ActiveRecord::Base.connection.select_all(command) p rows raise "OK" #abort all transactions for extra protection end rescue Exception => e error_message = e.message unless e.message == "OK" end end return {:error => error_message, :data => rows} end def get_info tables = [] table_names = ActiveRecord::Base.connection.tables.sort table_names.each do |table_name| tables << {:name => table_name, :columns => ActiveRecord::Base.connection.columns(table_name)} end return {:tables => tables, :error => nil} end end