Messenger bot starts to do the job

parent 405345c4
...@@ -149,3 +149,8 @@ ns2: 8.8.9.9 ...@@ -149,3 +149,8 @@ ns2: 8.8.9.9
host: q.unixmedia.net host: q.unixmedia.net
ip: auto ip: auto
[messenger]
app_secret:
verify_token:
page_token:
...@@ -3,16 +3,22 @@ ...@@ -3,16 +3,22 @@
from nevow import rend, inevow from nevow import rend, inevow
from corepost import Response, NotFoundException, AlreadyExistsException from corepost import Response, NotFoundException, AlreadyExistsException
from corepost.web import RESTResource, route, Http from corepost.web import RESTResource, route, Http
from corepost.convert import convertForSerialization, generateXml, convertToJson from corepost.convert import convertToJson
from corepost.enums import MediaType, HttpHeader from corepost.enums import MediaType, HttpHeader
from rest import RestCore as BotCore from dmlib.utils import webutils as wu
from rest import ResponseConversion
import hashlib import hashlib
import hmac import hmac
import six import six
try:
#python2
from urllib import urlencode
except ImportError:
#python3
from urllib.parse import urlencode
import logging import logging
log = logging.getLogger( 'Webgui' ) log = logging.getLogger( 'Webgui' )
...@@ -20,6 +26,14 @@ log = logging.getLogger( 'Webgui' ) ...@@ -20,6 +26,14 @@ log = logging.getLogger( 'Webgui' )
BOTResource = RESTResource BOTResource = RESTResource
class BotCore(object):
path = ""
def __init__(self, core, session):
self.core = core
self.session = session
class BaseBot(BotCore): class BaseBot(BotCore):
@route("/") @route("/")
...@@ -27,113 +41,152 @@ class BaseBot(BotCore): ...@@ -27,113 +41,152 @@ class BaseBot(BotCore):
return 'Domotika BOTs API interface V1.0' return 'Domotika BOTs API interface V1.0'
def messengerWrapResponse(f=None, uri=False, res_filter=None, *a, **kw):
if f and not callable(f):
uri=f
f=None
if f is None:
return partial(wrapResponse, uri=uri, *a, **kw)
def okResponse(res, u):
if isinstance(res, ResponseConversion):
entity=res.entity
if res_filter and callable(res_filter):
entity=res_filter(entity)
elif res_filter and hasattr(res_filter, '__iter__'):
for fil in res_filter:
if callable(fil):
entity=fil(entity)
entity={'result': 'succeed', 'data': entity, 'ts': time.time()}
if int(res.code) >= 400:
entity['result']='fail'
if uri:
entity['uri']=uri
elif u:
entity['uri']=u
r = ResponseConversion(res.request, res.code, entity, res.headers, res.ctype).getResponse()
else:
if res_filter and callable(res_filter):
res=res_filter(res)
elif res_filter and hasattr(res_filter, '__iter__'):
for fil in res_filter:
if callable(fil):
res=fil(res)
r={'result': 'succeed', 'data': res, 'ts': time.time()}
if uri:
r['uri']=uri
elif u:
r['uri']=u
return r
def errorResponse(res, u):
if isinstance(res, ResponseConversion):
entity={'result': 'fail', 'data': res.entity, 'ts': time.time()}
if uri:
entity['uri']=uri
elif u:
entity['uri']=u
r = ResponseConversion(res.request, res.code, entity, res.headers, res.ctype).getResponse()
else:
r={'result': 'fail', 'data': res, 'ts': time.time()}
if uri:
r['uri']=uri
elif u:
r['uri']=u
return r
@wraps(f)
def decorate(*a, **kw):
ruri=False
if len(a) > 1 and isinstance(a[1], Request):
ruri=a[1].uri
ret=defer.maybeDeferred(f, *a, **kw)
ret.addCallback(okResponse, ruri)
ret.addErrback(errorResponse, ruri)
return ret
return decorate
class MessengerBot(BotCore):
path = "/messenger"
def _getCfg(self, keyword):
return self.core.configGet('messenger', keyword)
def _validateHubSig(self, request_payload, hub_signature_header): def messengerValidator():
def checkRequest(f):
def new_f(self, request, *a, **kw):
if 'x-hub-signature' in request.getAllHeaders().keys():
hubsig=request.getHeader('x-hub-signature')
try: try:
hash_method, hub_signature = hub_signature_header.split('=') hash_method, hub_signature = hubsig.split('=')
except: except:
pass pass
else: else:
digest_module = getattr(hashlib, hash_method) digest_module = getattr(hashlib, hash_method)
hmac_object = hmac.new(str(self._cfgGet('app_secret')), unicode(request_payload), digest_module) hmac_object = hmac.new(str(self._cfgGet('app_secret')), unicode(request.content.getvalue()), digest_module)
generated_hash = hmac_object.hexdigest() generated_hash = hmac_object.hexdigest()
if hub_signature == generated_hash: if hub_signature == generated_hash:
return True return f(self, request, *a, **kw)
return False return Response(200, "Failed validation." )
new_f.funct_name = f.func_name
return new_f
return checkRequest
class MessengerBot(BotCore):
path = "messenger"
graphuri = 'https://graph.facebook.com/v2.6'
#graphuri = 'http://192.168.4.2/v2.6'
def __init__(self, *a, **kw):
super(MessengerBot, self).__init__(*a, **kw)
@property
def auth_args(self):
if not hasattr(self, '_auth_args'):
auth = {
'access_token': unicode(self._cfgGet('page_token'))
}
if self._cfgGet('app_secret') is not None and len(self._cfgGet('app_secret'))>0:
appsecret_proof = self._generateAppSecProof()
auth['appsecret_proof'] = appsecret_proof
self._auth_args = auth
return self._auth_args
def _cfgGet(self, keyword):
return self.core.configGet('messenger', keyword)
def _generateAppSecProof(self): def _generateAppSecProof(self):
if six.PY2: if six.PY2:
hmac_object = hmac.new(str(self._cfgGet('app_key')), unicode(self._cfgGet('page_token')), hashlib.sha256) hmac_object = hmac.new(str(self._cfgGet('app_secret')), unicode(self._cfgGet('page_token')), hashlib.sha256)
else: else:
hmac_object = hmac.new(bytearray(self._cfgGet('app_key'), 'utf8'), str(self._cfgGet('page_token')).encode('utf8'), hashlib.sha256) hmac_object = hmac.new(bytearray(self._cfgGet('app_secret'), 'utf8'), str(self._cfgGet('page_token')).encode('utf8'), hashlib.sha256)
return hmac_object.hexdigest() return hmac_object.hexdigest()
def _dataSent(self, res):
log.info('OKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOKOK')
log.info(res)
def _dataError(self, res):
log.info('=======================================================================')
log.info(res)
log.info(res.value.reasons[0].printTraceback())
def sendAPI(self, payload, req_uri='/me/messages'):
request_endpoint = self.graphuri+req_uri
request_uri = request_endpoint+'?'+urlencode(self.auth_args)
log.info("Sending message to "+str(request_uri)+" : "+str(convertToJson(payload)))
ctype={"Content-Type": "application/json"}
return wu.getPage(request_uri, method='POST', headers=ctype, postdata=convertToJson(payload)).addCallbacks(self._dataSent, self._dataError)
@route("/", Http.GET) @route("/", Http.GET)
def rootGet(self, request, *a, **kw): def rootGet(self, request, *a, **kw):
if 'hub.mode' in kw.keys() and kw['hub.mode'] == 'subscribe' and 'hub.challenge' in kw.keys(): if 'hub.mode' in kw.keys() and kw['hub.mode'] == 'subscribe' and 'hub.challenge' in kw.keys():
if 'hub.verify_token' in kw.keys() and kw['hub.verify_token'] == self._cfgGet('verify_token'): if 'hub.verify_token' in kw.keys() and kw['hub.verify_token'] == self._cfgGet('verify_token'):
log.info("New verification request for Messenger BOT: "+str(kw))
return kw['hub.challenge'] return kw['hub.challenge']
return Response(403, "Failed validation." ) return Response(403, "Failed validation." )
@route("/", Http.POST)
@messengerValidator()
def rootPost(self, request, *a, **kw):
log.debug("New messenger bot request: "+str(kw))
if 'object' in kw.keys() and kw['object'] == 'page' and 'entry' in kw.keys():
for entry in kw['entry']:
#try:
if True:
pageID=entry['id']
timestamp=entry['time']
messaging=entry['messaging']
for message in messaging:
msgkeys = message.keys()
if 'optin' in msgkeys:
self.receivedAuthentication(message)
elif 'message' in msgkeys:
self.receivedMessage(message)
elif 'delivery' in msgkeys:
self.receivedDeliveryConfirmation(message)
elif 'postback' in msgkeys:
self.receivedPostback(message)
elif 'read' in msgkeys:
self.receivedMessageRead(message)
elif 'account_linking' in msgkeys:
self.receivedAccountLink(message)
else:
log.info("Received unknow messaging webhook for messenger BOT: "+str(kw))
#except:
# pass
return Response(200, 'OK')
def receivedAuthentication(self, msg):
pass
def receivedMessage(self, msg):
log.info("Messenger bot received message: "+str(msg))
message = u'Received: '+unicode(msg['message']['text'])
if not 'is_echo' in msg['message'].keys() or not msg['message']['is_echo']:
self.sendMessage(msg['sender']['id'], message)
def receivedDeliveryConfirmation(self, msg):
pass
def receivedPostback(self, msg):
pass
def receivedMessageRead(self, msg):
log.info("Messenger bot received message read: "+str(msg))
def receivedAccountLink(self, msg):
pass
def sendMessage(self, recipient_id, message):
payload = {
'recipient': {
'id': recipient_id
},
'message': {
'text': message
}
}
return self.sendAPI(payload)
BotApiList=( BotApiList=(
BaseBot, BaseBot,
MessengerBot MessengerBot
......
...@@ -361,6 +361,12 @@ class SessionWrapper(guard.SessionWrapper): ...@@ -361,6 +361,12 @@ class SessionWrapper(guard.SessionWrapper):
mp = mediaproxy.MediaStreamProxy() mp = mediaproxy.MediaStreamProxy()
mp.core = self.core mp.core = self.core
return (mp, segments[1:]) return (mp, segments[1:])
if name.startswith('bot'):
# Bypass for chat bots
chatbot = bot.BotPages()
chatbot.core = self.core
return (chatbot, segments[1:])
for n in self.core.configGet('proxy', 'localproxypathsnologin').split(','): for n in self.core.configGet('proxy', 'localproxypathsnologin').split(','):
if n and name.startswith(n): if n and name.startswith(n):
log.info("Proxy Bypass localproxypathsnologin locateChild "+name) log.info("Proxy Bypass localproxypathsnologin locateChild "+name)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment