Skip to content

Commit 4ef2dc3

Browse files
committed
feat(replay): Track custom masking usage via fake integration
1 parent 0eaac1e commit 4ef2dc3

2 files changed

Lines changed: 88 additions & 7 deletions

File tree

sentry/src/main/java/io/sentry/SentryReplayOptions.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.sentry;
22

3+
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;
4+
35
import io.sentry.protocol.SdkVersion;
46
import io.sentry.util.SampleRateUtils;
57
import java.util.ArrayList;
@@ -16,6 +18,8 @@
1618

1719
public final class SentryReplayOptions {
1820

21+
private static final String CUSTOM_MASKING_INTEGRATION_NAME = "ReplayCustomMasking";
22+
1923
public static final String TEXT_VIEW_CLASS_NAME = "android.widget.TextView";
2024
public static final String IMAGE_VIEW_CLASS_NAME = "android.widget.ImageView";
2125
public static final String WEB_VIEW_CLASS_NAME = "android.webkit.WebView";
@@ -209,8 +213,9 @@ public enum SentryReplayQuality {
209213

210214
public SentryReplayOptions(final boolean empty, final @Nullable SdkVersion sdkVersion) {
211215
if (!empty) {
212-
setMaskAllText(true);
213-
setMaskAllImages(true);
216+
// Add default mask classes directly without setting usingCustomMasking flag
217+
maskViewClasses.add(TEXT_VIEW_CLASS_NAME);
218+
maskViewClasses.add(IMAGE_VIEW_CLASS_NAME);
214219
maskViewClasses.add(WEB_VIEW_CLASS_NAME);
215220
maskViewClasses.add(VIDEO_VIEW_CLASS_NAME);
216221
maskViewClasses.add(ANDROIDX_MEDIA_VIEW_CLASS_NAME);
@@ -275,11 +280,12 @@ public void setSessionSampleRate(final @Nullable Double sessionSampleRate) {
275280
* <p>Default is enabled.
276281
*/
277282
public void setMaskAllText(final boolean maskAllText) {
283+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
278284
if (maskAllText) {
279-
addMaskViewClass(TEXT_VIEW_CLASS_NAME);
285+
maskViewClasses.add(TEXT_VIEW_CLASS_NAME);
280286
unmaskViewClasses.remove(TEXT_VIEW_CLASS_NAME);
281287
} else {
282-
addUnmaskViewClass(TEXT_VIEW_CLASS_NAME);
288+
unmaskViewClasses.add(TEXT_VIEW_CLASS_NAME);
283289
maskViewClasses.remove(TEXT_VIEW_CLASS_NAME);
284290
}
285291
}
@@ -293,11 +299,12 @@ public void setMaskAllText(final boolean maskAllText) {
293299
* <p>Default is enabled.
294300
*/
295301
public void setMaskAllImages(final boolean maskAllImages) {
302+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
296303
if (maskAllImages) {
297-
addMaskViewClass(IMAGE_VIEW_CLASS_NAME);
304+
maskViewClasses.add(IMAGE_VIEW_CLASS_NAME);
298305
unmaskViewClasses.remove(IMAGE_VIEW_CLASS_NAME);
299306
} else {
300-
addUnmaskViewClass(IMAGE_VIEW_CLASS_NAME);
307+
unmaskViewClasses.add(IMAGE_VIEW_CLASS_NAME);
301308
maskViewClasses.remove(IMAGE_VIEW_CLASS_NAME);
302309
}
303310
}
@@ -308,6 +315,7 @@ public Set<String> getMaskViewClasses() {
308315
}
309316

310317
public void addMaskViewClass(final @NotNull String className) {
318+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
311319
this.maskViewClasses.add(className);
312320
}
313321

@@ -317,6 +325,7 @@ public Set<String> getUnmaskViewClasses() {
317325
}
318326

319327
public void addUnmaskViewClass(final @NotNull String className) {
328+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
320329
this.unmaskViewClasses.add(className);
321330
}
322331

@@ -351,12 +360,14 @@ public long getSessionDuration() {
351360

352361
@ApiStatus.Internal
353362
public void setMaskViewContainerClass(@NotNull String containerClass) {
354-
addMaskViewClass(containerClass);
363+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
364+
maskViewClasses.add(containerClass);
355365
maskViewContainerClass = containerClass;
356366
}
357367

358368
@ApiStatus.Internal
359369
public void setUnmaskViewContainerClass(@NotNull String containerClass) {
370+
addIntegrationToSdkVersion(CUSTOM_MASKING_INTEGRATION_NAME);
360371
unmaskViewContainerClass = containerClass;
361372
}
362373

sentry/src/test/java/io/sentry/SentryReplayOptionsTest.kt

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
package io.sentry
22

3+
import kotlin.test.BeforeTest
34
import kotlin.test.Test
45
import kotlin.test.assertEquals
6+
import kotlin.test.assertFalse
57
import kotlin.test.assertTrue
68

79
class SentryReplayOptionsTest {
10+
11+
@BeforeTest
12+
fun setup() {
13+
SentryIntegrationPackageStorage.getInstance().clearStorage()
14+
}
15+
816
@Test
917
fun `uses medium quality as default`() {
1018
val replayOptions = SentryReplayOptions(true, null)
@@ -126,4 +134,66 @@ class SentryReplayOptionsTest {
126134
assertTrue(headers.contains("X-Response-Header"))
127135
assertTrue(headers.contains("X-Debug-Header"))
128136
}
137+
138+
// Custom Masking Integration Tests
139+
140+
private fun hasCustomMaskingIntegration(): Boolean {
141+
return SentryIntegrationPackageStorage.getInstance()
142+
.integrations
143+
.contains("ReplayCustomMasking")
144+
}
145+
146+
@Test
147+
fun `default options does not add ReplayCustomMasking integration`() {
148+
SentryReplayOptions(false, null)
149+
assertFalse(hasCustomMaskingIntegration())
150+
}
151+
152+
@Test
153+
fun `empty options does not add ReplayCustomMasking integration`() {
154+
SentryReplayOptions(true, null)
155+
assertFalse(hasCustomMaskingIntegration())
156+
}
157+
158+
@Test
159+
fun `addUnmaskViewClass adds ReplayCustomMasking integration`() {
160+
val options = SentryReplayOptions(false, null)
161+
options.addUnmaskViewClass("com.example.MyTextView")
162+
assertTrue(hasCustomMaskingIntegration())
163+
}
164+
165+
@Test
166+
fun `setMaskViewContainerClass adds ReplayCustomMasking integration`() {
167+
val options = SentryReplayOptions(false, null)
168+
options.setMaskViewContainerClass("com.example.MyContainer")
169+
assertTrue(hasCustomMaskingIntegration())
170+
}
171+
172+
@Test
173+
fun `setUnmaskViewContainerClass adds ReplayCustomMasking integration`() {
174+
val options = SentryReplayOptions(false, null)
175+
options.setUnmaskViewContainerClass("com.example.MyContainer")
176+
assertTrue(hasCustomMaskingIntegration())
177+
}
178+
179+
@Test
180+
fun `addMaskViewClass adds ReplayCustomMasking integration`() {
181+
val options = SentryReplayOptions(false, null)
182+
options.addMaskViewClass("com.example.MySensitiveView")
183+
assertTrue(hasCustomMaskingIntegration())
184+
}
185+
186+
@Test
187+
fun `setMaskAllText adds ReplayCustomMasking integration`() {
188+
val options = SentryReplayOptions(false, null)
189+
options.setMaskAllText(false)
190+
assertTrue(hasCustomMaskingIntegration())
191+
}
192+
193+
@Test
194+
fun `setMaskAllImages adds ReplayCustomMasking integration`() {
195+
val options = SentryReplayOptions(false, null)
196+
options.setMaskAllImages(false)
197+
assertTrue(hasCustomMaskingIntegration())
198+
}
129199
}

0 commit comments

Comments
 (0)