""" This is the webhook server that interfaces with Google's WebSub (formerly pubsubhubbub) server. This can be run either as a module on the main frontend, or as its own server, so it can live on a different host than the frontend. """ import time import sqlite3 from flask import Flask, Blueprint, request from urllib.parse import parse_qs, urlparse from ..common.common import * frontend = Blueprint('webhooks', __name__) def app(): app = Flask(__name__) app.register_blueprint(frontend) return app @frontend.route('/websub/v1////', methods=["GET"]) def websub(timestamp, nonce, subject, sig): hmackey = cf['websub']['hmac_key'] mode = request.args.get('hub.mode', '') topic = request.args.get('hub.topic', '') challenge = request.args.get('hub.challenge', '') until = int(request.args.get('hub.lease_seconds', '0')) if sig != websub_url_hmac(hmackey, subject, timestamp, nonce): return '', 400 if time.time() - timestamp > int(cf['websub']['lease']): return '', 400 if mode != "subscribe": return '', 200 # Note: channels are not purged from the websub dbtable. with sqlite3.connect(cf['global']['database']) as conn: c = conn.cursor() c.execute(""" INSERT OR REPLACE INTO websub (channel_id, subscribed_until) VALUES (?, datetime(?, 'unixepoch')) """, (subject, time.time()+until)) return challenge, 200 @frontend.route('/websub/v1////', methods=["POST"]) def websub_post(timestamp, nonce, subject, sig): lease = cf['websub']['lease'] hmackey = cf['websub']['hmac_key'] hub_signature = request.headers.get('X-Hub-Signature').replace("sha1=", "") if sig != websub_url_hmac(hmackey, subject, timestamp, nonce): return '', 400 if hub_signature != websub_body_hmac(hmackey, request.data): return '', 400 with sqlite3.connect(cf['global']['database']) as conn: c = conn.cursor() try: update_channel(conn, request.data, from_webhook=True) except Exception as e: app.logger.error(e) with open('/tmp/websub-subscriptions.err', 'ab') as f: f.write(f"\n".encode('ascii')) f.write(request.data + b"\n") return '', 200 if __name__ == '__main__': app().run(debug=True)