# ======================================================================================== # # FOLLOWZUP PROJECT # # ======================================================================================== # # Copyright (C) 2016 Followzup.com # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/> # # ======================================================================================== ## # Contributor: Dener Carmo # E-mail: dener.wilian at gmail.com # https://github.com/denerblack ## require 'base64' require 'openssl' require 'uri' require 'net/http' require 'rexml/document' require 'byebug' require 'mcrypt' ################################################################################ # https://sourceforge.net/projects/mcrypt/files/Libmcrypt/ # # Install the gem: # # gem install ruby-mcrypt --test -- --with-mcrypt-dir=/path/to/mcrypt/prefix # # More info: # # https://github.com/kingpong/ruby-mcrypt#mcrypt---libmcrypt-bindings-for-ruby # ################################################################################ class fzup_#idchannel# attr_accessor :fzup_channel attr_accessor :fzup_pubkey64 attr_accessor :fzup_pubkey attr_accessor :fzup_lastseq attr_accessor :fzup_retcode attr_accessor :fzup_retframe FZUP_URI = URI("http://www.followzup.com/wschannel") INVALID_SEQUENCE = "6101" PSEUDO_KEY = OpenSSL::Random.pseudo_bytes(16) IV = 0.chr * 16; def initialize @fzup_channel = "#idchannel#" @fzup_lastseq = 0 @fzup_pubkey64 = "#pubkey64#" @fzup_pubkey = Base64.decode64(fzup_pubkey64) end def decrypt(fzup_encrypted_url) puts fzup_encrypted_url url_decoded = URI.decode(fzup_encrypted_url) url_decoded_base64 = Base64.decode64(url_decoded) rsa_key = OpenSSL::PKey::RSA.new(fzup_pubkey) rsa_key.public_decrypt(url_decoded_base64) end def submit(fzup_tab = {}) fzup_param = { "FZUP_COMMAND" => "", "FZUP_LASTSEQ" => "0", "FZUP_MESSAGEID" => "", "FZUP_SUBSCODE" => "", "FZUP_USER" => "", "FZUP_HOURS" => "0", "FZUP_MSGTEXT" => "", "FZUP_MSGURL" => "" } fzup_tab.each do |key, value| fzup_param[key] = value if fzup_param.has_key?(key) end seq = fzup_param["FZUP_LASTSEQ"].to_i fzup_lastseq = seq > 0 ? seq : 0 cmd = fzup_param["FZUP_COMMAND"] return ["6103", fzup_lastseq.to_s, "<?xml version=\"1.0\" encoding=\"utf-8\"?><followzup></followzup>"] unless cmd.eql?("chck") || cmd.eql?("smsg") begin @fzup_lastseq += 1 plain = build_xml(cmd, @fzup_lastseq, fzup_param["FZUP_USER"], fzup_param["FZUP_SUBSCODE"], fzup_param["FZUP_HOURS"], Base64::encode64(fzup_param["FZUP_MSGTEXT"]), Base64::encode64(fzup_param["FZUP_MSGURL"])) crypt_data = mcrypt(plain) rsa_key = OpenSSL::PKey::RSA.new(fzup_pubkey) key_2 = rsa_key.public_encrypt(PSEUDO_KEY) data = Base64.encode64(crypt_data) key_3 = Base64.encode64(key_2) response = send_data(key_3, data) response_xml = REXML::Document.new(response.body) unless response_xml.to_s.empty? @retframe = "" response_xml.elements.each('followzup/retcode') {|z| @fzup_retcode = z.text } response_xml.elements.each('followzup/retframe') {|z| @retframe = z.text } retframe_decoded = Base64.decode64(@retframe) retframe_mcrypt = mcrypt(retframe_decoded, :decrypt) fzup_retframe = REXML::Document.new(retframe_mcrypt) fzup_retframe.elements.each('followzup/seq') { |z| @fzup_lastseq = z.text.to_i } if fzup_retcode.eql?(INVALID_SEQUENCE) end end while fzup_retcode.eql?('6101') [fzup_retcode, fzup_lastseq, fzup_retframe.to_s] end private def mcrypt(data, type = :encrypt) enc = Mcrypt.new(:rijndael_128, :cbc, PSEUDO_KEY, IV, :zeros) encrypted = type.eql?(:encrypt) ? enc.encrypt(data) : enc.decrypt(data) encrypted end def send_data(key, data) request = Net::HTTP::Post.new(FZUP_URI) request.initialize_http_header({"User-Agent" => "wschannel: #{fzup_channel}"}) request.set_form_data('id' => fzup_channel, 'key' => key, 'frame'=> data) response = Net::HTTP.start(FZUP_URI.hostname, FZUP_URI.port) do |http| http.request(request) end response end def build_xml(cmd, fzup_lastseq, user, subscode, hours, msgtext, msgurl) xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" xml << "<followzup>" xml << "<com>#{cmd}</com>" xml << "<seq>#{fzup_lastseq}</seq>" case cmd when "chck" xml << "<usr>#{user}</usr>" xml << "<sub>#{subscode}</sub>" when "smsg" xml << "<usr>#{user}</usr>" xml << "<hrs>#{hours}</hrs>" xml << "<msg>#{msgtext}</msg>" xml << "<url>#{msgurl}</url>" end xml << "</followzup>" xml end end