Skip to content

Instantly share code, notes, and snippets.

@henryyang42
Created July 5, 2017 02:10
Show Gist options
  • Save henryyang42/f313a2d9f9fbbe0ee7a09bffb92650b1 to your computer and use it in GitHub Desktop.
Save henryyang42/f313a2d9f9fbbe0ee7a09bffb92650b1 to your computer and use it in GitHub Desktop.
import hashlib
import time
import xmltodict
from flask import Flask, request
app = Flask(__name__)
WECHAT_TOKEN = "wechat_token"
# Check if the message XML is valid, this simple bot handles TEXT messages only!
# To learn more about the supported types of messages and how to implement them, see:
# Common Messages: http://admin.wechat.com/wiki/index.php?title=Common_Messages
# Event Messages: http://admin.wechat.com/wiki/index.php?title=Event-based_Messages
# Speech Recognition Messages:
# http://admin.wechat.com/wiki/index.php?title=Speech_Recognition_Messages
def validate_message(message):
return (
message is not None and
message['xml'] != None and
message['xml']['MsgType'] != None and
message['xml']['MsgType'] == 'text' and
message['xml']['Content'] != None
)
# Format the reply according to the WeChat XML format for synchronous replies,
# see: http://admin.wechat.com/wiki/index.php?title=Callback_Messages
def format_message(original_message, content):
return (
"<xml>"
"<ToUserName><![CDATA[%s]]></ToUserName>"
"<FromUserName><![CDATA[%s]]></FromUserName>"
"<CreateTime>%s</CreateTime>"
"<MsgType><![CDATA[text]]></MsgType>"
"<Content><![CDATA[%s]]></Content>"
"</xml>"
) % (
# From and To must be inverted in replies ;)
original_message['xml']['FromUserName'],
original_message['xml']['ToUserName'], # Same as above!
time.gmtime(),
content
)
def verify_backend(request):
# Get the parameters from the query string
signature = request.args.get('signature')
timestamp = request.args.get('timestamp')
nonce = request.args.get('nonce')
echostr = request.args.get('echostr')
# Compute the signature (note that the shared token is used too)
verification_elements = [WECHAT_TOKEN, timestamp, nonce]
verification_elements.sort()
verification_string = "".join(verification_elements)
verification_string = hashlib.sha1(
verification_string.encode('utf-8')).hexdigest()
# If the signature is correct, output the same "echostr" provided by
# the WeChat server as a parameter
if signature == verification_string:
return echostr
else:
return ""
@app.route('/wechat', methods=['GET', 'POST'])
def echo_server():
error = None
if request.method == 'GET':
# The WeChat server will issue a GET request in order to verify the chatbot backend server upon configuration.
return verify_backend(request)
elif request.method == 'POST':
# Messages will be POSTed from the WeChat server to the chatbot backend server,
# see: http://admin.wechat.com/wiki/index.php?title=Common_Messages
message = xmltodict.parse(request.data)
# If the message is valid, echo it back to the user or send an error message.
# Some kind of response, even an empty one, is *REQUIRED* by WeChat
# within the mandatory timeout limit of 5 seconds.
# Otherwise, the user will see an error in the app.
if validate_message(message):
reply = "You typed: %s" % (message['xml']['Content'])
return format_message(message, reply)
else:
return "Message was sent in a wrong format."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment