Skip to content

Commit ed0476f

Browse files
vaindadinauer
authored andcommitted
Merge pull request #2359 from getsentry/release/6.7.0
2 parents 642001e + f5173a1 commit ed0476f

File tree

10 files changed

+156
-16
lines changed

10 files changed

+156
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## Unreleased
3+
## 6.7.0
44

55
### Fixes
66

sentry-android-okhttp/src/main/java/io/sentry/android/okhttp/SentryOkHttpInterceptor.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import io.sentry.exception.SentryHttpClientException
1616
import io.sentry.protocol.Mechanism
1717
import io.sentry.util.HttpUtils
1818
import io.sentry.util.PropagationTargetsUtils
19+
import io.sentry.util.UrlUtils
1920
import okhttp3.Headers
2021
import okhttp3.Interceptor
2122
import okhttp3.Request
@@ -53,7 +54,7 @@ class SentryOkHttpInterceptor(
5354
override fun intercept(chain: Interceptor.Chain): Response {
5455
var request = chain.request()
5556

56-
val url = request.url.toString()
57+
val url = UrlUtils.maybeStripSensitiveDataFromUrl(request.url.toString(), hub.options.isSendDefaultPii)
5758
val method = request.method
5859

5960
// read transaction from the bound scope
@@ -96,7 +97,8 @@ class SentryOkHttpInterceptor(
9697
} finally {
9798
finishSpan(span, request, response)
9899

99-
val breadcrumb = Breadcrumb.http(request.url.toString(), request.method, code)
100+
val url = UrlUtils.maybeStripSensitiveDataFromUrl(request.url.toString(), hub.options.isSendDefaultPii)
101+
val breadcrumb = Breadcrumb.http(url, request.method, code)
100102
request.body?.contentLength().ifHasValidLength {
101103
breadcrumb.setData("request_body_size", it)
102104
}
@@ -180,7 +182,7 @@ class SentryOkHttpInterceptor(
180182
hint.set(OKHTTP_RESPONSE, response)
181183

182184
val sentryRequest = io.sentry.protocol.Request().apply {
183-
url = requestUrl
185+
url = UrlUtils.maybeStripSensitiveDataFromUrl(requestUrl, hub.options.isSendDefaultPii)
184186
// Cookie is only sent if isSendDefaultPii is enabled
185187
cookies = if (hub.options.isSendDefaultPii) request.headers["Cookie"] else null
186188
method = request.method

sentry-apollo-3/src/main/java/io/sentry/apollo3/SentryApollo3HttpInterceptor.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import io.sentry.SentryLevel
1717
import io.sentry.SpanStatus
1818
import io.sentry.TypeCheckHint
1919
import io.sentry.util.PropagationTargetsUtils
20+
import io.sentry.util.UrlUtils
2021

2122
class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IHub = HubAdapter.getInstance(), private val beforeSpan: BeforeSpanCallback? = null) :
2223
HttpInterceptor {
@@ -80,7 +81,7 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IH
8081
}
8182

8283
private fun startChild(request: HttpRequest, activeSpan: ISpan): ISpan {
83-
val url = request.url
84+
val url = UrlUtils.maybeStripSensitiveDataFromUrl(request.url, hub.options.isSendDefaultPii)
8485
val method = request.method
8586

8687
val operationName = operationNameFromHeaders(request)
@@ -121,8 +122,9 @@ class SentryApollo3HttpInterceptor @JvmOverloads constructor(private val hub: IH
121122
}
122123
span.finish()
123124

125+
val url = UrlUtils.maybeStripSensitiveDataFromUrl(request.url, hub.options.isSendDefaultPii)
124126
val breadcrumb =
125-
Breadcrumb.http(request.url, request.method.name, statusCode)
127+
Breadcrumb.http(url, request.method.name, statusCode)
126128

127129
request.body?.contentLength.ifHasValidLength { contentLength ->
128130
breadcrumb.setData("request_body_size", contentLength)

sentry-apollo/src/main/java/io/sentry/apollo/SentryApolloInterceptor.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.sentry.SentryLevel
2121
import io.sentry.SpanStatus
2222
import io.sentry.TypeCheckHint.APOLLO_REQUEST
2323
import io.sentry.TypeCheckHint.APOLLO_RESPONSE
24+
import io.sentry.util.UrlUtils
2425
import java.util.concurrent.Executor
2526

2627
class SentryApolloInterceptor(
@@ -114,7 +115,8 @@ class SentryApolloInterceptor(
114115
val httpResponse = it.httpResponse.get()
115116
val httpRequest = httpResponse.request()
116117

117-
val breadcrumb = Breadcrumb.http(httpRequest.url().toString(), httpRequest.method(), httpResponse.code())
118+
val url = UrlUtils.maybeStripSensitiveDataFromUrl(httpRequest.url().toString(), hub.options.isSendDefaultPii)
119+
val breadcrumb = Breadcrumb.http(url, httpRequest.method(), httpResponse.code())
118120

119121
httpRequest.body()?.contentLength().ifHasValidLength { contentLength ->
120122
breadcrumb.setData("request_body_size", contentLength)

sentry-openfeign/src/main/java/io/sentry/openfeign/SentryFeignClient.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.sentry.SpanStatus;
1616
import io.sentry.util.Objects;
1717
import io.sentry.util.PropagationTargetsUtils;
18+
import io.sentry.util.UrlUtils;
1819
import java.io.IOException;
1920
import java.util.ArrayList;
2021
import java.util.Collection;
@@ -50,7 +51,9 @@ public Response execute(final @NotNull Request request, final @NotNull Request.O
5051
}
5152

5253
ISpan span = activeSpan.startChild("http.client");
53-
String url = request.url();
54+
final @NotNull String url =
55+
UrlUtils.maybeStripSensitiveDataFromUrl(
56+
request.url(), hub.getOptions().isSendDefaultPii());
5457
span.setDescription(request.httpMethod().name() + " " + url);
5558

5659
final RequestWrapper requestWrapper = new RequestWrapper(request);
@@ -99,11 +102,11 @@ public Response execute(final @NotNull Request request, final @NotNull Request.O
99102
}
100103

101104
private void addBreadcrumb(final @NotNull Request request, final @Nullable Response response) {
105+
final @NotNull String url =
106+
UrlUtils.maybeStripSensitiveDataFromUrl(request.url(), hub.getOptions().isSendDefaultPii());
102107
final Breadcrumb breadcrumb =
103108
Breadcrumb.http(
104-
request.url(),
105-
request.httpMethod().name(),
106-
response != null ? response.status() : null);
109+
url, request.httpMethod().name(), response != null ? response.status() : null);
107110
breadcrumb.setData("request_body_size", request.body() != null ? request.body().length : 0);
108111
if (response != null && response.body() != null && response.body().length() != null) {
109112
breadcrumb.setData("response_body_size", response.body().length());

sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/tracing/SentrySpanClientHttpRequestInterceptor.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import io.sentry.SpanStatus;
1515
import io.sentry.util.Objects;
1616
import io.sentry.util.PropagationTargetsUtils;
17+
import io.sentry.util.UrlUtils;
18+
1719
import java.io.IOException;
1820
import org.jetbrains.annotations.NotNull;
1921
import org.jetbrains.annotations.Nullable;
@@ -47,7 +49,8 @@ public SentrySpanClientHttpRequestInterceptor(final @NotNull IHub hub) {
4749
final ISpan span = activeSpan.startChild("http.client");
4850
final String methodName =
4951
request.getMethod() != null ? request.getMethod().name() : "unknown";
50-
span.setDescription(methodName + " " + request.getURI());
52+
final @NotNull String url = UrlUtils.maybeStripSensitiveDataFromUrl(request.getURI().toString(), hub.getOptions().isSendDefaultPii());
53+
span.setDescription(methodName + " " + url);
5154

5255
final SentryTraceHeader sentryTraceHeader = span.toSentryTrace();
5356

@@ -87,9 +90,10 @@ private void addBreadcrumb(
8790
final @Nullable Integer responseStatusCode,
8891
final @Nullable ClientHttpResponse response) {
8992
final String methodName = request.getMethod() != null ? request.getMethod().name() : "unknown";
93+
final @NotNull String url = UrlUtils.maybeStripSensitiveDataFromUrl(request.getURI().toString(), hub.getOptions().isSendDefaultPii());
9094

9195
final Breadcrumb breadcrumb =
92-
Breadcrumb.http(request.getURI().toString(), methodName, responseStatusCode);
96+
Breadcrumb.http(url, methodName, responseStatusCode);
9397
breadcrumb.setData("request_body_size", body.length);
9498

9599
final Hint hint = new Hint();

sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpanClientHttpRequestInterceptor.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import io.sentry.SpanStatus;
1515
import io.sentry.util.Objects;
1616
import io.sentry.util.PropagationTargetsUtils;
17+
import io.sentry.util.UrlUtils;
1718
import java.io.IOException;
1819
import org.jetbrains.annotations.NotNull;
1920
import org.jetbrains.annotations.Nullable;
@@ -47,7 +48,10 @@ public SentrySpanClientHttpRequestInterceptor(final @NotNull IHub hub) {
4748
final ISpan span = activeSpan.startChild("http.client");
4849
final String methodName =
4950
request.getMethod() != null ? request.getMethod().name() : "unknown";
50-
span.setDescription(methodName + " " + request.getURI());
51+
final @NotNull String url =
52+
UrlUtils.maybeStripSensitiveDataFromUrl(
53+
request.getURI().toString(), hub.getOptions().isSendDefaultPii());
54+
span.setDescription(methodName + " " + url);
5155

5256
final SentryTraceHeader sentryTraceHeader = span.toSentryTrace();
5357

@@ -88,8 +92,10 @@ private void addBreadcrumb(
8892
final @Nullable ClientHttpResponse response) {
8993
final String methodName = request.getMethod() != null ? request.getMethod().name() : "unknown";
9094

91-
final Breadcrumb breadcrumb =
92-
Breadcrumb.http(request.getURI().toString(), methodName, responseStatusCode);
95+
final @NotNull String url =
96+
UrlUtils.maybeStripSensitiveDataFromUrl(
97+
request.getURI().toString(), hub.getOptions().isSendDefaultPii());
98+
final Breadcrumb breadcrumb = Breadcrumb.http(url, methodName, responseStatusCode);
9399
breadcrumb.setData("request_body_size", body.length);
94100

95101
final Hint hint = new Hint();

sentry/api/sentry.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3379,6 +3379,12 @@ public final class io/sentry/util/StringUtils {
33793379
public static fun removeSurrounding (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
33803380
}
33813381

3382+
public final class io/sentry/util/UrlUtils {
3383+
public fun <init> ()V
3384+
public static fun maybeStripSensitiveDataFromUrl (Ljava/lang/String;Z)Ljava/lang/String;
3385+
public static fun maybeStripSensitiveDataFromUrlNullable (Ljava/lang/String;Z)Ljava/lang/String;
3386+
}
3387+
33823388
public class io/sentry/vendor/Base64 {
33833389
public static final field CRLF I
33843390
public static final field DEFAULT I
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.sentry.util;
2+
3+
import java.util.regex.Matcher;
4+
import java.util.regex.Pattern;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
public final class UrlUtils {
9+
10+
private static final @NotNull Pattern USER_INFO_REGEX = Pattern.compile("(.+://)(.*@)(.*)");
11+
private static final @NotNull Pattern TOKEN_REGEX = Pattern.compile("(.*)([?&]token=[^&#]+)(.*)");
12+
13+
public static @Nullable String maybeStripSensitiveDataFromUrlNullable(
14+
final @Nullable String url, final boolean isSendDefaultPii) {
15+
if (url == null) {
16+
return null;
17+
}
18+
19+
return maybeStripSensitiveDataFromUrl(url, isSendDefaultPii);
20+
}
21+
22+
public static @NotNull String maybeStripSensitiveDataFromUrl(
23+
final @NotNull String url, final boolean isSendDefaultPii) {
24+
if (isSendDefaultPii) {
25+
return url;
26+
}
27+
28+
@NotNull String modifiedUrl = url;
29+
30+
Matcher userInfoMatcher = USER_INFO_REGEX.matcher(modifiedUrl);
31+
if (userInfoMatcher.matches() && userInfoMatcher.groupCount() == 3) {
32+
final @NotNull String userInfoString = userInfoMatcher.group(2);
33+
final @NotNull String replacementString = userInfoString.contains(":") ? "%s:%s@" : "%s@";
34+
modifiedUrl = userInfoMatcher.group(1) + replacementString + userInfoMatcher.group(3);
35+
}
36+
37+
Matcher tokenMatcher = TOKEN_REGEX.matcher(modifiedUrl);
38+
if (tokenMatcher.matches() && tokenMatcher.groupCount() == 3) {
39+
final @NotNull String tokenString = tokenMatcher.group(2);
40+
final @NotNull String queryParamSeparator = tokenString.substring(0, 1);
41+
modifiedUrl =
42+
tokenMatcher.group(1) + queryParamSeparator + "token=%s" + tokenMatcher.group(3);
43+
}
44+
45+
return modifiedUrl;
46+
}
47+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package io.sentry.util
2+
3+
import kotlin.test.Test
4+
import kotlin.test.assertEquals
5+
import kotlin.test.assertNull
6+
7+
class UrlUtilsTest {
8+
9+
@Test
10+
fun `returns null for null`() {
11+
assertNull(UrlUtils.maybeStripSensitiveDataFromUrlNullable(null, false))
12+
}
13+
14+
@Test
15+
fun `keeps sensitive data if sendDefaultPii is true`() {
16+
assertEquals("https://user:[email protected]?q=1&s=2&token=secret#top", UrlUtils.maybeStripSensitiveDataFromUrl("https://user:[email protected]?q=1&s=2&token=secret#top", true))
17+
}
18+
19+
@Test
20+
fun `strips user info with user and password`() {
21+
assertEquals("http://%s:%[email protected]", UrlUtils.maybeStripSensitiveDataFromUrl("http://user:[email protected]", false))
22+
}
23+
24+
@Test
25+
fun `strips user info with user and password from https`() {
26+
assertEquals("https://%s:%[email protected]", UrlUtils.maybeStripSensitiveDataFromUrl("https://user:[email protected]", false))
27+
}
28+
29+
@Test
30+
fun `strips user info with user only`() {
31+
assertEquals("http://%[email protected]", UrlUtils.maybeStripSensitiveDataFromUrl("http://[email protected]", false))
32+
}
33+
34+
@Test
35+
fun `strips user info with user only from https`() {
36+
assertEquals("https://%[email protected]", UrlUtils.maybeStripSensitiveDataFromUrl("https://[email protected]", false))
37+
}
38+
39+
@Test
40+
fun `strips token from query params as first param`() {
41+
assertEquals("https://sentry.io?token=%s", UrlUtils.maybeStripSensitiveDataFromUrl("https://sentry.io?token=secret", false))
42+
}
43+
44+
@Test
45+
fun `strips token from query params as later param`() {
46+
assertEquals("https://sentry.io?q=1&s=2&token=%s", UrlUtils.maybeStripSensitiveDataFromUrl("https://sentry.io?q=1&s=2&token=secret", false))
47+
}
48+
49+
@Test
50+
fun `strips token from query params as first param and keeps anchor`() {
51+
assertEquals("https://sentry.io?token=%s#top", UrlUtils.maybeStripSensitiveDataFromUrl("https://sentry.io?token=secret#top", false))
52+
}
53+
54+
@Test
55+
fun `strips token from query params as later param and keeps anchor`() {
56+
assertEquals("https://sentry.io?q=1&s=2&token=%s#top", UrlUtils.maybeStripSensitiveDataFromUrl("https://sentry.io?q=1&s=2&token=secret#top", false))
57+
}
58+
59+
@Test
60+
fun `strips token from query params after anchor`() {
61+
assertEquals("https://api.github.com/users/getsentry/repos/#fragment?token=%s", UrlUtils.maybeStripSensitiveDataFromUrl("https://api.github.com/users/getsentry/repos/#fragment?token=query", false))
62+
}
63+
64+
@Test
65+
fun `strips token from query params after anchor with &`() {
66+
assertEquals("https://api.github.com/users/getsentry/repos/#fragment?q=1&token=%s", UrlUtils.maybeStripSensitiveDataFromUrl("https://api.github.com/users/getsentry/repos/#fragment?q=1&token=query", false))
67+
}
68+
}

0 commit comments

Comments
 (0)