mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	sentry: Provide a server-side tunnel.
Some well-intentioned adblockers also block Sentry client-side error reporting. Provide an endpoint on the Zulip server which forwards to the Sentry server, so that these requests are not blocked.
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							926cb84ca5
						
					
				
				
					commit
					93bfd3fb5f
				
			@@ -15,6 +15,7 @@ IGNORED_PHRASES = [
 | 
			
		||||
    r"Botserver",
 | 
			
		||||
    r"Cookie Bot",
 | 
			
		||||
    r"DevAuthBackend",
 | 
			
		||||
    r"DSN",
 | 
			
		||||
    r"GCM",
 | 
			
		||||
    r"GitHub",
 | 
			
		||||
    r"Gravatar",
 | 
			
		||||
 
 | 
			
		||||
@@ -137,6 +137,8 @@ not_yet_fully_covered = [
 | 
			
		||||
    "zerver/webhooks/teamcity/view.py",
 | 
			
		||||
    "zerver/webhooks/travis/view.py",
 | 
			
		||||
    "zerver/webhooks/zapier/view.py",
 | 
			
		||||
    # This is hard to get test coverage for, and low value to do so
 | 
			
		||||
    "zerver/views/sentry.py",
 | 
			
		||||
    # Cannot have coverage, as tests run in a transaction
 | 
			
		||||
    "zerver/lib/safe_session_cached_db.py",
 | 
			
		||||
    "zerver/lib/singleton_bmemcached.py",
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ if (page_params.server_sentry_dsn) {
 | 
			
		||||
    Sentry.init({
 | 
			
		||||
        dsn: page_params.server_sentry_dsn,
 | 
			
		||||
        environment: page_params.server_sentry_environment || "development",
 | 
			
		||||
        tunnel: "/error_tracing",
 | 
			
		||||
 | 
			
		||||
        release: "zulip-server@" + ZULIP_VERSION,
 | 
			
		||||
        integrations: [
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								zerver/views/sentry.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								zerver/views/sentry.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
import urllib
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
from django.utils.translation import gettext as _
 | 
			
		||||
from django.views.decorators.csrf import csrf_exempt
 | 
			
		||||
 | 
			
		||||
from zerver.lib.exceptions import JsonableError
 | 
			
		||||
from zerver.lib.outgoing_http import OutgoingSession
 | 
			
		||||
from zerver.lib.validator import (
 | 
			
		||||
    check_url,
 | 
			
		||||
    to_wild_value,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SentryTunnelSession(OutgoingSession):
 | 
			
		||||
    def __init__(self) -> None:
 | 
			
		||||
        super().__init__(role="sentry_tunnel", timeout=5)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@csrf_exempt
 | 
			
		||||
def sentry_tunnel(
 | 
			
		||||
    request: HttpRequest,
 | 
			
		||||
) -> HttpResponse:
 | 
			
		||||
    try:
 | 
			
		||||
        envelope = request.body
 | 
			
		||||
        header = to_wild_value("envelope", envelope.split(b"\n")[0].decode("utf-8"))
 | 
			
		||||
        dsn = urllib.parse.urlparse(header["dsn"].tame(check_url))
 | 
			
		||||
    except Exception:
 | 
			
		||||
        raise JsonableError(_("Invalid request format"))
 | 
			
		||||
 | 
			
		||||
    if dsn.geturl() != settings.SENTRY_FRONTEND_DSN:
 | 
			
		||||
        raise JsonableError(_("Invalid DSN"))
 | 
			
		||||
 | 
			
		||||
    assert dsn.hostname
 | 
			
		||||
    project_id = dsn.path.strip("/")
 | 
			
		||||
    url = dsn._replace(netloc=dsn.hostname, path=f"/api/{project_id}/envelope/").geturl()
 | 
			
		||||
    SentryTunnelSession().post(
 | 
			
		||||
        url=url, data=envelope, headers={"Content-Type": "application/x-sentry-envelope"}
 | 
			
		||||
    ).raise_for_status()
 | 
			
		||||
    return HttpResponse(status=200)
 | 
			
		||||
@@ -137,6 +137,7 @@ from zerver.views.report import (
 | 
			
		||||
    report_send_times,
 | 
			
		||||
    report_unnarrow_times,
 | 
			
		||||
)
 | 
			
		||||
from zerver.views.sentry import sentry_tunnel
 | 
			
		||||
from zerver.views.storage import get_storage, remove_storage, update_storage
 | 
			
		||||
from zerver.views.streams import (
 | 
			
		||||
    add_default_stream,
 | 
			
		||||
@@ -790,6 +791,10 @@ urls += [
 | 
			
		||||
    path("scim/v2/", include("django_scim.urls", namespace="scim")),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# Front-end Sentry requests tunnel through the server, if enabled
 | 
			
		||||
if settings.SENTRY_FRONTEND_DSN:
 | 
			
		||||
    urls += [path("error_tracing", sentry_tunnel)]
 | 
			
		||||
 | 
			
		||||
# User documentation site
 | 
			
		||||
help_documentation_view = MarkdownDirectoryView.as_view(
 | 
			
		||||
    template_name="zerver/documentation_main.html",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user