From 19a1733e72b8185808bbd267041d9c43b3ec2c23 Mon Sep 17 00:00:00 2001
From: Robin Sonnabend <robin@fsmpi.rwth-aachen.de>
Date: Sat, 10 Mar 2018 23:02:46 +0100
Subject: [PATCH] Add support for reporting issues to sentry

---
 .flake8           |  3 +++
 config.py.example |  3 +++
 requirements.txt  |  5 +++++
 server.py         | 29 ++++++++++++++++++++++++++++-
 utils.py          |  7 ++++++-
 5 files changed, 45 insertions(+), 2 deletions(-)
 create mode 100644 .flake8

diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..8b84e38
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+ignore = E402,W503
+
diff --git a/config.py.example b/config.py.example
index 581ca22..5c4cd15 100644
--- a/config.py.example
+++ b/config.py.example
@@ -25,6 +25,9 @@ CELERY_BROKER_URL = "redis://localhost:6379/0" # change this if you do not use r
 CELERY_TASK_SERIALIZER = "pickle" # do not change
 CELERY_ACCEPT_CONTENT = ["pickle"] # do not change
 
+# Send exceptions to sentry (optional)
+# SENTRY_DSN = "https://********:********@sentry.example.com//1"
+
 # CUPS printserver (optional)
 PRINTING_ACTIVE = True
 PRINTING_SERVER = "printsrv.example.com:631"
diff --git a/requirements.txt b/requirements.txt
index a5143e5..3e871ca 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -17,6 +17,7 @@ curtsies==0.3.0
 enum-compat==0.0.2
 eventlet==0.22.1
 feedgen==0.6.1
+flake8==3.5.0
 Flask==0.12.2
 Flask-Migrate==2.1.1
 Flask-Script==2.0.6
@@ -34,11 +35,14 @@ ldap3==2.4.1
 lxml==4.1.1
 Mako==1.0.7
 MarkupSafe==1.0
+mccabe==0.6.1
 nose==1.3.7
 packaging==16.8
 pathtools==0.1.2
 psycopg2==2.7.4
 pyasn1==0.4.2
+pycodestyle==2.3.1
+pyflakes==1.6.0
 Pygments==2.2.0
 pyldap==2.4.45
 pyparsing==2.2.0
@@ -50,6 +54,7 @@ python-pam==1.8.2
 python-socketio==1.8.4
 pytz==2018.3
 PyYAML==3.12
+raven==6.6.0
 redis==2.10.6
 regex==2018.2.8
 requests==2.18.4
diff --git a/server.py b/server.py
index e7010e1..8c10bcb 100755
--- a/server.py
+++ b/server.py
@@ -31,7 +31,7 @@ from shared import (
 from utils import (
     get_first_unused_int, get_etherpad_text, split_terms, optional_int_arg,
     fancy_join, footnote_hash, get_git_revision, get_max_page_length_exp,
-    get_internal_filename, get_csrf_token)
+    get_internal_filename, get_csrf_token, get_current_ip)
 from decorators import (
     db_lookup, protect_csrf,
     require_private_view_right, require_modify_right, require_publish_right,
@@ -64,10 +64,37 @@ migrate = Migrate(app, db)
 manager = Manager(app)
 manager.add_command("db", MigrateCommand)
 
+try:
+    from raven.contrib.flask import Sentry
+    sentry = Sentry(app, dsn=config.SENTRY_DSN)
+
+    def get_user_info(request):
+        return {
+            "is_authenticated": check_login(),
+            "ip_address": get_current_ip(),
+            "release": get_git_revision(),
+        }
+    sentry.get_user_info = get_user_info
+except ModuleNotFoundError:
+    print("Raven not installed. Not sending issues to Sentry.")
+except AttributeError:
+    print("DSN not configured. Not sending issues to Sentry.")
+
 
 def make_celery(app, config):
     celery = Celery(app.import_name, broker=config.CELERY_BROKER_URL)
     celery.conf.update(app.config)
+    try:
+        from raven import Client as RavenClient
+        from raven.contrib.celery import (
+            register_signal, register_logger_signal)
+        raven_client = RavenClient(config.SENTRY_DSN)
+        register_logger_signal(raven_client)
+        register_signal(raven_client)
+    except ModuleNotFoundError:
+        print("Raven not installed. Not sending celery issues to Sentry.")
+    except AttributeError:
+        print("DSN not configured. Not sending celery issues to Sentry.")
     return celery
 
 
diff --git a/utils.py b/utils.py
index 5e80b9c..116a2f1 100644
--- a/utils.py
+++ b/utils.py
@@ -193,11 +193,16 @@ def add_line_numbers(text):
     return "\n".join(lines)
 
 
-def check_ip_in_networks(networks_string):
+def get_current_ip():
     address = ipaddress.ip_address(request.remote_addr)
     if (address == ipaddress.ip_address("127.0.0.1")
             and "X-Real-Ip" in request.headers):
         address = ipaddress.ip_address(request.headers["X-Real-Ip"])
+    return address
+
+
+def check_ip_in_networks(networks_string):
+    address = get_current_ip()
     try:
         for network_string in networks_string.split(","):
             network = ipaddress.ip_network(network_string.strip())
-- 
GitLab