Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
D
domotikad
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
domotika
domotikad
Commits
be595c32
Commit
be595c32
authored
8 years ago
by
Franco (nextime) Lanza
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Messenger bot starts to do the job
parent
405345c4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
151 additions
and
87 deletions
+151
-87
domotikad.conf
conf/defaults/domotikad.conf
+5
-0
bot.py
domotika/web/bot.py
+140
-87
web.py
domotika/web/web.py
+6
-0
No files found.
conf/defaults/domotikad.conf
View file @
be595c32
...
...
@@ -149,3 +149,8 @@ ns2: 8.8.9.9
host
:
q
.
unixmedia
.
net
ip
:
auto
[
messenger
]
app_secret
:
verify_token
:
page_token
:
This diff is collapsed.
Click to expand it.
domotika/web/bot.py
View file @
be595c32
...
...
@@ -3,16 +3,22 @@
from
nevow
import
rend
,
inevow
from
corepost
import
Response
,
NotFoundException
,
AlreadyExistsException
from
corepost.web
import
RESTResource
,
route
,
Http
from
corepost.convert
import
convert
ForSerialization
,
generateXml
,
convert
ToJson
from
corepost.convert
import
convertToJson
from
corepost.enums
import
MediaType
,
HttpHeader
from
rest
import
RestCore
as
BotCore
from
rest
import
ResponseConversion
from
dmlib.utils
import
webutils
as
wu
import
hashlib
import
hmac
import
six
try
:
#python2
from
urllib
import
urlencode
except
ImportError
:
#python3
from
urllib.parse
import
urlencode
import
logging
log
=
logging
.
getLogger
(
'Webgui'
)
...
...
@@ -20,6 +26,14 @@ log = logging.getLogger( 'Webgui' )
BOTResource
=
RESTResource
class
BotCore
(
object
):
path
=
""
def
__init__
(
self
,
core
,
session
):
self
.
core
=
core
self
.
session
=
session
class
BaseBot
(
BotCore
):
@
route
(
"/"
)
...
...
@@ -27,113 +41,152 @@ class BaseBot(BotCore):
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
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
:
hash_method
,
hub_signature
=
hubsig
.
split
(
'='
)
except
:
pass
else
:
digest_module
=
getattr
(
hashlib
,
hash_method
)
hmac_object
=
hmac
.
new
(
str
(
self
.
_cfgGet
(
'app_secret'
)),
unicode
(
request
.
content
.
getvalue
()),
digest_module
)
generated_hash
=
hmac_object
.
hexdigest
()
if
hub_signature
==
generated_hash
:
return
f
(
self
,
request
,
*
a
,
**
kw
)
return
Response
(
200
,
"Failed validation."
)
new_f
.
funct_name
=
f
.
func_name
return
new_f
return
checkRequest
@
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
class
MessengerBot
(
BotCore
):
return
decorate
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
)
class
MessengerBot
(
BotCore
):
@
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
path
=
"/messenger"
def
_
getCfg
(
self
,
keyword
):
def
_
cfgGet
(
self
,
keyword
):
return
self
.
core
.
configGet
(
'messenger'
,
keyword
)
def
_validateHubSig
(
self
,
request_payload
,
hub_signature_header
):
try
:
hash_method
,
hub_signature
=
hub_signature_header
.
split
(
'='
)
except
:
pass
else
:
digest_module
=
getattr
(
hashlib
,
hash_method
)
hmac_object
=
hmac
.
new
(
str
(
self
.
_cfgGet
(
'app_secret'
)),
unicode
(
request_payload
),
digest_module
)
generated_hash
=
hmac_object
.
hexdigest
()
if
hub_signature
==
generated_hash
:
return
True
return
False
def
_generateAppSecProof
(
self
):
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
:
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
()
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
)
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.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
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
=
(
BaseBot
,
MessengerBot
...
...
This diff is collapsed.
Click to expand it.
domotika/web/web.py
View file @
be595c32
...
...
@@ -361,6 +361,12 @@ class SessionWrapper(guard.SessionWrapper):
mp
=
mediaproxy
.
MediaStreamProxy
()
mp
.
core
=
self
.
core
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
(
','
):
if
n
and
name
.
startswith
(
n
):
log
.
info
(
"Proxy Bypass localproxypathsnologin locateChild "
+
name
)
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment