module Wechat::Responder

Public Instance Methods

create() click to toggle source
# File lib/wechat/responder.rb, line 187
def create
  request_msg = Wechat::Message.from_hash(post_body)
  response_msg = run_responder(request_msg)

  if response_msg.respond_to? :to_xml
    render plain: process_response(response_msg)
  else
    head :ok, content_type: 'text/html'
  end

  response_msg.save_session if response_msg.is_a?(Wechat::Message) && Wechat.config.have_session_class

  ActiveSupport::Notifications.instrument 'wechat.responder.after_create', request: request_msg, response: response_msg
end
show() click to toggle source
# File lib/wechat/responder.rb, line 178
def show
  if @we_corpid.present?
    echostr, _corp_id = unpack(decrypt(Base64.decode64(params[:echostr]), @we_encoding_aes_key))
    render plain: echostr
  else
    render plain: params[:echostr]
  end
end

Private Instance Methods

config_account() click to toggle source
# File lib/wechat/responder.rb, line 204
def config_account
  account = self.class.account_from_request&.call(request)
  config = account ? Wechat.config(account) : nil

  @we_encrypt_mode = config&.encrypt_mode || self.class.encrypt_mode
  @we_encoding_aes_key = config&.encoding_aes_key || self.class.encoding_aes_key
  @we_token = config&.token || self.class.token
  @we_corpid = config&.corpid || self.class.corpid
end
gen_msg(encrypt, timestamp, nonce) click to toggle source
# File lib/wechat/responder.rb, line 292
def gen_msg(encrypt, timestamp, nonce)
  msg_sign = Signature.hexdigest(@we_token, timestamp, nonce, encrypt)

  { Encrypt: encrypt,
    MsgSignature: msg_sign,
    TimeStamp: timestamp,
    Nonce: nonce }.to_xml(root: 'xml', children: 'item', skip_instruct: true, skip_types: true)
end
post_body() click to toggle source
# File lib/wechat/responder.rb, line 230
def post_body
  if request.media_type == 'application/json'
    data_hash = params

    if @we_encrypt_mode && data['Encrypt'].present?
      content, @we_app_id = unpack(decrypt(Base64.decode64(data['Encrypt']), @we_encoding_aes_key))
      data_hash = content
    end

    data_hash = data_hash.to_unsafe_hash if data_hash.instance_of?(ActionController::Parameters)
    HashWithIndifferentAccess.new(data_hash).tap do |msg|
      msg[:Event]&.downcase!
    end
  else
    post_xml
  end
end
post_xml() click to toggle source
# File lib/wechat/responder.rb, line 248
def post_xml
  data = request_content

  if @we_encrypt_mode && request_encrypt_content.present?
    content, @we_app_id = unpack(decrypt(Base64.decode64(request_encrypt_content), @we_encoding_aes_key))
    data = Hash.from_xml(content)
  end

  data_hash = data.fetch('xml', {})
  data_hash = data_hash.to_unsafe_hash if data_hash.instance_of?(ActionController::Parameters)
  HashWithIndifferentAccess.new(data_hash).tap do |msg|
    msg[:Event]&.downcase!
  end
end
process_response(response) click to toggle source
# File lib/wechat/responder.rb, line 281
def process_response(response)
  msg = response[:MsgType] == 'success' ? 'success' : response.to_xml

  if @we_encrypt_mode
    encrypt = Base64.strict_encode64(encrypt(pack(msg, @we_app_id), @we_encoding_aes_key))
    msg = gen_msg(encrypt, params[:timestamp], params[:nonce])
  end

  msg
end
request_content() click to toggle source
# File lib/wechat/responder.rb, line 305
def request_content
  params[:xml].nil? ? Hash.from_xml(request.raw_post) : { 'xml' => params[:xml] }
end
request_encrypt_content() click to toggle source
# File lib/wechat/responder.rb, line 301
def request_encrypt_content
  request_content&.dig('xml', 'Encrypt')
end
run_responder(request) click to toggle source
# File lib/wechat/responder.rb, line 263
def run_responder(request)
  self.class.responder_for(request) do |responder, *args|
    responder ||= self.class.user_defined_responders(:fallback).first

    next if responder.nil?

    if responder[:respond]
      request.reply.text responder[:respond]
    elsif responder[:proc]
      define_singleton_method :process, responder[:proc]
      number_of_block_parameter = responder[:proc].arity
      send(:process, *args.unshift(request).take(number_of_block_parameter))
    else
      next
    end
  end
end
verify_signature() click to toggle source
# File lib/wechat/responder.rb, line 214
def verify_signature
  if @we_encrypt_mode
    signature = params[:signature] || params[:msg_signature]
    msg_encrypt = params[:echostr] || request_encrypt_content
  else
    signature = params[:signature]
  end

  msg_encrypt = nil unless @we_corpid.present?

  render plain: 'Forbidden', status: 403 if signature != Signature.hexdigest(@we_token,
                                                                             params[:timestamp],
                                                                             params[:nonce],
                                                                             msg_encrypt)
end