ging/social_stream

View on GitHub
presence/ejabberd/ejabberd_scripts/rest_api_client_script

Summary

Maintainability
Test Coverage
#!/usr/bin/env ruby
####################################
#      Rest Api Client Script 
#Generate and send requests to Social Stream presence API
#@author Aldo Gordillo < agordillos@gmail.com >
#@version 2.0 - 24-2-2012
####################################


require 'logger'
require 'rest_client'

path = "/var/log/ejabberd/scripts.log"
file = File.open(path, File::WRONLY | File::APPEND | File::CREAT)
file.sync = true
$logger = Logger.new(file)
$logger.level = Logger::DEBUG

def getOption(option)
  File.open('/etc/ejabberd/ssconfig.cfg', 'r') do |f1|  
    while line = f1.gets  
      line = line.gsub(/\n/,'')
      if line.match(/^#/)
        #Comments
      elsif line.match(/^#{option}/)
        return line.gsub(/#{option}/,'')
      end  
    end  
  end
  return "Undefined"
end

#Constants
$secure_rest_api = getOption("secure_rest_api=")
$pass = getOption("ejabberd_password=")
$scripts_path = getOption("scripts_path=")
$script_title = "Rest Api Client"


def log(title,text)
    $logger.info title + ": " + text
end

def getMethodName
  caller[0] =~ /`(.*?)'/
  $1
end


#####################
#####  Example  #####
#####################
#def myHook(param1,param2)
#    log(getMethodName,"(My message: #{param1},#{param2})")
#    url = "http://" + getWebDomainUrlFromDomain(domain) + "/xmpp/hookRoute"

#    params = {}
#    encrypted_params = {}
#    #Add params to sent in clear
#    params[:param1_in_server]=param1
#    #Add params to sent cipher
#    encrypted_params[:param2_in_server]=param2

#    return [getMethodName,generic_api_call(url,params,encrypted_params)]
#end

def setConnection(userJid)
    log($script_title,"#{getMethodName}(#{userJid})")
    url = "http://" + getWebDomainUrlFromDomain(getDomainFromJid(userJid)) + "/xmpp/setConnection"

    params = {}
    encrypted_params = {}
    encrypted_params[:name]=getUsernameFromJid(userJid)

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end


def unsetConnection(userJid)
    log($script_title,"#{getMethodName}(#{userJid})")
    url = "http://" +  getWebDomainUrlFromDomain(getDomainFromJid(userJid)) + "/xmpp/unsetConnection"

    params = {}
    encrypted_params = {}
    encrypted_params[:name]=getUsernameFromJid(userJid)

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end


def setPresence(userJid,status)
    log($script_title,"#{getMethodName}(#{userJid},#{status})")
    url = "http://" + getWebDomainUrlFromDomain(getDomainFromJid(userJid)) + "/xmpp/setPresence"

    params = {}
    encrypted_params = {}
    encrypted_params[:name]=getUsernameFromJid(userJid)
    encrypted_params[:status]=status

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end


def unsetPresence(userJid)
    log($script_title,"#{getMethodName}(#{userJid})")
    url = "http://" + getWebDomainUrlFromDomain(getDomainFromJid(userJid)) + "/xmpp/unsetPresence"

    params = {}
    encrypted_params = {}
    encrypted_params[:name]=getUsernameFromJid(userJid)

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end


#Reset all domains connections
def resetConnection()
    log($script_title,"Call #{getMethodName}()")
    url = "http://" + getWebDomainUrlFromDomain("all") + "/xmpp/resetConnection"

    params = {}
    encrypted_params = {}

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end


def synchronize(domain)
    log($script_title,"Call #{getMethodName}(#{domain})")
    url = "http://" + getWebDomainUrlFromDomain(domain) + "/xmpp/synchronizePresence"
    
    #Get connected users using Emanagement
    jids = []
    if domain=="all"
    command = $scripts_path + "/emanagement getConnectedJids"
    else
    command = $scripts_path + "/emanagement getConnectedJidsByDomain " + domain
    end
    output = %x[#{command}]
    sessions = output.split("\n")

    sessions.each do |session|
      jids << session.split("/")[0]
    end
    #Finish

    #In this cases users always will be sent in clear (not cipher)
    #(Too much data to cipher)
    #Anyway, we must to build the hash to pass the authentication
    params = {}
    encrypted_params = {}
    params[:name]=jids.join(",")

    return [getMethodName,generic_api_call(url,params,encrypted_params)]
end



#Params must include the password and all the parameters to be sent in clear.
#Anyway, If "secure_rest_api" is disable, encrypted_params will be send in clear.
def generic_api_call(url,params,encrypted_params)

  begin
    unless params
     params = {}
    end

    unless encrypted_params
      encrypted_params = {}
    end

    params[:password]=$pass

    response=sendHttpRequest(url,params,encrypted_params)
    puts response.body

    if response.body.include?("Ok")
        return true
    else
        return false
    end

  rescue => e
    log($script_title,"#{e.class.name}: #{e.message}")
    puts("#{e.class.name}: #{e.message}")
    return false
  end
end


#Send HTTP Request to Social Stream Presence API
def sendHttpRequest(url,params,encrypted_params)

    unless params[:password]
    return "params[:password] required in sendHttpRequest";
    end


    if $secure_rest_api == "true"
    #Require libraries
    require 'openssl'

    xmpp_private_key_path = $scripts_path + "/rsa_keys/xmpp_rsa_key_private.pem";
        web_public_key_path = $scripts_path + "/rsa_keys/web_rsa_key_public.pem";
        xmpp_private_key = OpenSSL::PKey::RSA.new(File.read(xmpp_private_key_path))
        web_public_key = OpenSSL::PKey::RSA.new(File.read(web_public_key_path))

    request_params = {};

    #Copy non encypted params
        params.each do |key,value|
      unless key.to_s == "password"
        request_params[key] = value
      end 
        end

    #Include encrypted params
    if encrypted_params and encrypted_params.empty? == false
      request_params[:encrypted_params] = web_public_key.public_encrypt(encrypted_params.to_s)
    end
    
    #Generating stamp
    #1 Get constant password
    password = params[:password];
    #2 Generating timestamp
    timestamp = Time.now.utc.to_s
    #3 Calculating Hash
        hash = calculateHash(request_params)

    #Add cipher stamp to the request
    request_params[:password] = xmpp_private_key.private_encrypt(password+"#####"+timestamp+"#####"+hash)
    
    #Replace previous params
    params = request_params
    else
    #Non secure mode: send encrypted params in clear
    if encrypted_params
      encrypted_params.each do |key,value|
          params[key] = value
      end
    end
    end
    
    response = RestClient.get url, :params => params
    return response
end


def calculateHash(request_params)
    require 'digest/md5'

    unless request_params
        request_params = {};
    end

    hash = "";
        request_params.each do |key,value|
              hash = hash + key.to_s + value.to_s
        end
        return Digest::MD5.hexdigest(hash)
end




def invokeApiCall(method,args)
    length = args.length;
    case length
    when 0
      return send(method)
    when 1
      return send(method,args[0])
    when 2
      return send(method,args[0],args[1])
    when 3
      return send(method,args[0],args[1],args[2])
    when 4
      return send(method,args[0],args[1],args[2],args[3])
    else
      return send(method,args)
    end
end


def getUsernameFromJid(jid)
    return jid.split("@")[0];
end

def getDomainFromJid(jid)
    return jid.split("@")[1];
end

def getWebDomainUrlFromDomain(domain)

    if domain=="all"
      return getWebDomainUrlFromDomain(getWebDomains()[0])
    end

    web_domain = getOption(domain + "=");
    if (web_domain != "Undefined")
        return web_domain
    else
        return domain
    end
end

def getWebDomains()
    begin
        web_domains = getOption("web_domains=");
        #web_domains=["domain1","domain2"]
        return getElementsFromStringArray(web_domains);
    rescue Exception=>e
        return [""]
    end
end

def getElementsFromStringArray(stringArray)
    stringArray=stringArray[1,stringArray.length-2]
    return stringArray.split(",")
end


#Main Program

begin

    args = []
    method = ARGV[0];
    ARGV.each do |arg|
        args.push(arg)
    end
    args.shift;

    if (response = invokeApiCall(method, args) and response[1])
          puts $script_title  + ": #{response[0]} [OK]"
          log( $script_title  , "#{response[0]} [OK]" )
    else
          puts $script_title  + ": #{response[0]} [FAIL]"
          log( $script_title  , "#{response[0]} [FAIL]" )
    end

rescue => e
    log($script_title,"#{e.class.name}: #{e.message}")
       puts("#{e.class.name}: #{e.message}")
        exit 1
end