Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/sentry/conf/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,7 @@ def build_cdc_postgres_init_db_volume(settings):
# - 'https://browser.sentry-cdn.com/6.19.7/bundle.min.js' will stay the same.
JS_SDK_LOADER_DEFAULT_SDK_URL = ""


# block domains which are generally used by spammers -- keep this configurable
# in case a self-hosted install wants to allow it
INVALID_EMAIL_ADDRESS_PATTERN = re.compile(r"\@qq\.com$", re.I)
Expand Down
69 changes: 69 additions & 0 deletions src/sentry/web/frontend/js_sdk_dynamic_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from typing import Optional, Tuple, TypedDict

from rest_framework.request import Request
from rest_framework.response import Response

from sentry.loader.browsersdkversion import get_browser_sdk_version
from sentry.models import Project, ProjectKey
from sentry.web.frontend.base import BaseView


class SdkConfig(TypedDict):
dsn: str


class LoaderContext(TypedDict):
config: SdkConfig
jsSdkUrl: Optional[str]
publicKey: Optional[str]


class JavaScriptSdkDynamicLoader(BaseView):
auth_required = False

# Do not let an organization load trigger session, breaking Vary header.
# TODO: This view should probably not be a subclass of BaseView if it doesn't actually use the
# large amount of organization related support utilities, but that ends up being a large refactor.
def determine_active_organization(self, request: Request, organization_slug=None) -> None:
pass

def _get_bundle_kind_modifier(self) -> str:
"""Returns a string that is used to modify the bundle name"""
bundle_kind_modifier = ""

# if tracing
bundle_kind_modifier += ".tracing"

# if replay
bundle_kind_modifier += ".replay"

# if es5
bundle_kind_modifier += ".es5"

# if debug
bundle_kind_modifier += ".debug"

return bundle_kind_modifier

def _get_context(self, key: str) -> Tuple[LoaderContext, Optional[str], Optional[str]]:
"""Sets context information needed to render the loader"""
if not key:
return ({}, None, None)

sdk_version = get_browser_sdk_version(key)

# TODO(abhi): Right now this loader only supports returning es6 JS bundles.
# We may want to re-evaluate this.

return ({}, sdk_version, None)

def get(self, request: Request, public_key: str, minified: str) -> Response:
"""Returns a JS file that dynamically loads the SDK based on project settings"""
key = None

try:
key = ProjectKey.objects.get_from_cache(public_key=public_key)
except ProjectKey.DoesNotExist:
pass
else:
key.project = Project.objects.get_from_cache(id=key.project_id)
7 changes: 7 additions & 0 deletions src/sentry/web/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from sentry.web.frontend.group_tag_export import GroupTagExportView
from sentry.web.frontend.home import HomeView
from sentry.web.frontend.idp_email_verification import AccountConfirmationView
from sentry.web.frontend.js_sdk_dynamic_loader import JavaScriptSdkDynamicLoader
from sentry.web.frontend.js_sdk_loader import JavaScriptSdkLoader
from sentry.web.frontend.mailgun_inbound_webhook import MailgunInboundWebhookView
from sentry.web.frontend.newest_performance_issue import NewestPerformanceIssueView
Expand Down Expand Up @@ -116,6 +117,12 @@
JavaScriptSdkLoader.as_view(),
name="sentry-js-sdk-loader",
),
# Javascript SDK Loader
url(
r"^js-sdk-loader/(?P<public_key>[^/\.]+)(?:(?P<minified>\.min))?\.js$",
JavaScriptSdkDynamicLoader.as_view(),
name="sentry-js-sdk-loader",
),
# Versioned API
url(r"^api/0/", include("sentry.api.urls")),
# Legacy unversioned endpoints
Expand Down
31 changes: 31 additions & 0 deletions tests/sentry/web/frontend/test_js_sdk_dynamic_loader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
from django.conf import settings

from sentry.testutils import TestCase


class JavaScriptSdkDynamicLoaderTest(TestCase):
@pytest.fixture(autouse=True)
def set_settings(self):
settings.JS_SDK_LOADER_SDK_VERSION = "7.36.0"
settings.JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle%s.min.js"

def test_noop_no_pub_key(self):
# When given no public key, respond with the noop template
pass

def test_noop(self):
# When given a public key, but no default SDK URL, respond with the noop template
pass

def test_no_replace(self):
# When given a public key, and a default SDK URL, but the SDK version is not set, respond with the noop template
pass

def test_renders_js_loader(self):
# When given a public key, and a default SDK URL, and the SDK version is set, respond with the js loader template
pass

def test_minified(self):
# When given a public key, and a default SDK URL, and the SDK version is set, respond with the minified js loader template
pass