]>
git.gir.st - subscriptionfeed.git/blob - app/webhooks/__init__.py
2 This is the webhook server that interfaces with Google's WebSub (formerly
3 pubsubhubbub) server. This can be run either as a module on the main frontend,
4 or as its own server, so it can live on a different host than the frontend.
9 from flask
import Flask
, Blueprint
, request
10 from urllib
.parse
import parse_qs
, urlparse
12 from ..common
.common
import *
13 from ..common
.anticsrf
import no_csrf_protection
14 from ..common
.anticaptcha
import solve_captcha
16 frontend
= Blueprint('webhooks', __name__
)
20 app
.register_blueprint(frontend
)
23 @frontend.route('/websub')
25 return '', 204 # No Content
27 @frontend.route('/websub/v1/<int:timestamp>/<nonce>/<subject>/<sig>', methods
=["GET"])
28 def websub(timestamp
, nonce
, subject
, sig
):
29 hmackey
= cf
['websub']['hmac_key']
30 mode
= request
.args
.get('hub.mode', '')
31 topic
= request
.args
.get('hub.topic', '')
32 challenge
= request
.args
.get('hub.challenge', '')
33 until
= int(request
.args
.get('hub.lease_seconds', '0'))
35 if sig
!= websub_url_hmac(hmackey
, subject
, timestamp
, nonce
):
38 if time
.time() - timestamp
> int(cf
['websub']['lease']):
41 if mode
!= "subscribe":
43 # Note: channels are not purged from the websub dbtable.
45 with sqlite3
.connect(cf
['global']['database']) as conn
:
48 INSERT OR REPLACE INTO websub (channel_id, subscribed_until)
49 VALUES (?, datetime(?, 'unixepoch'))
50 """, (subject
, time
.time()+until
))
53 @frontend.route('/websub/v1/<int:timestamp>/<nonce>/<subject>/<sig>', methods
=["POST"])
55 def websub_post(timestamp
, nonce
, subject
, sig
):
56 lease
= cf
['websub']['lease']
57 hmackey
= cf
['websub']['hmac_key']
58 hub_signature
= request
.headers
.get('X-Hub-Signature').replace("sha1=", "")
60 if sig
!= websub_url_hmac(hmackey
, subject
, timestamp
, nonce
):
62 if hub_signature
!= websub_body_hmac(hmackey
, request
.data
):
65 with sqlite3
.connect(cf
['global']['database']) as conn
:
68 update_channel(conn
, request
.data
, from_webhook
=True)
69 except Exception as e
:
70 with
open('/tmp/websub-subscriptions.err', 'ab') as f
:
71 f
.write(f
"<!-- {time.ctime()} ({int(time.time())}) -->\n".encode('ascii'))
72 f
.write(request
.data
+ b
"\n")
76 @frontend.route("/captcha_response/v1/<nonce>", methods
=["POST"])
78 def captcha_response(nonce
):
79 solve_captcha(nonce
, request
.json
)
82 if __name__
== '__main__':