Skip to content

Commit

Permalink
fix(replay): RN Classes to redact were not used by cocoa
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich committed Nov 7, 2024
1 parent f9c38c7 commit b4e79be
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */; };
336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */; };
33958C692BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */; };
33AFDFED2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */; };
Expand All @@ -18,11 +19,13 @@
/* Begin PBXFileReference section */
1482D5685A340AB93348A43D /* Pods-RNSentryCocoaTesterTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RNSentryCocoaTesterTests.release.xcconfig"; path = "Target Support Files/Pods-RNSentryCocoaTesterTests/Pods-RNSentryCocoaTesterTests.release.xcconfig"; sourceTree = "<group>"; };
330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryBreadcrumb.h; path = ../ios/RNSentryBreadcrumb.h; sourceTree = "<group>"; };
332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryReplayOptionsTests.swift; sourceTree = "<group>"; };
332D33482CDBDC7300547D76 /* RNSentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentry.h; path = ../ios/RNSentry.h; sourceTree = SOURCE_ROOT; };
336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RNSentryReplayBreadcrumbConverterTests.swift; sourceTree = "<group>"; };
3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryReplayBreadcrumbConverter.h; path = ../ios/RNSentryReplayBreadcrumbConverter.h; sourceTree = "<group>"; };
3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNSentryBreadcrumbTests.swift; sourceTree = "<group>"; };
3360898D29524164007C7730 /* RNSentryCocoaTesterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RNSentryCocoaTesterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
338739072A7D7D2800950DDD /* RNSentryTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNSentryTests.h; sourceTree = "<group>"; };
338739072A7D7D2800950DDD /* RNSentryReplay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNSentryReplay.h; path = ../ios/RNSentryReplay.h; sourceTree = "<group>"; };
33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNSentryOnDrawReporter.h; path = ../ios/RNSentryOnDrawReporter.h; sourceTree = "<group>"; };
33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryOnDrawReporterTests.m; sourceTree = "<group>"; };
33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNSentryFramesTrackerListenerTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -80,24 +83,26 @@
children = (
336084382C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift */,
33F58ACF2977037D008F60EA /* RNSentryTests.mm */,
338739072A7D7D2800950DDD /* RNSentryTests.h */,
33AFDFEC2B8D14B300AAB120 /* RNSentryFramesTrackerListenerTests.m */,
33AFDFEE2B8D14C200AAB120 /* RNSentryFramesTrackerListenerTests.h */,
33AFDFF02B8D15E500AAB120 /* RNSentryDependencyContainerTests.m */,
33AFDFF22B8D15F600AAB120 /* RNSentryDependencyContainerTests.h */,
33958C682BFCF12600AD1FB6 /* RNSentryOnDrawReporterTests.m */,
3360843C2C340C76008CC412 /* RNSentryBreadcrumbTests.swift */,
332D33462CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift */,
);
path = RNSentryCocoaTesterTests;
sourceTree = "<group>";
};
33AFE0122B8F319000AAB120 /* RNSentry */ = {
isa = PBXGroup;
children = (
332D33482CDBDC7300547D76 /* RNSentry.h */,
3360843A2C32E3A8008CC412 /* RNSentryReplayBreadcrumbConverter.h */,
330F308D2C0F385A002A0D4E /* RNSentryBreadcrumb.h */,
33958C672BFCEF5A00AD1FB6 /* RNSentryOnDrawReporter.h */,
33AFE0132B8F31AF00AAB120 /* RNSentryDependencyContainer.h */,
338739072A7D7D2800950DDD /* RNSentryReplay.h */,
);
name = RNSentry;
sourceTree = "<group>";
Expand Down Expand Up @@ -212,6 +217,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
332D33472CDBDBB600547D76 /* RNSentryReplayOptionsTests.swift in Sources */,
33AFDFF12B8D15E500AAB120 /* RNSentryDependencyContainerTests.m in Sources */,
336084392C32E382008CC412 /* RNSentryReplayBreadcrumbConverterTests.swift in Sources */,
33F58AD02977037D008F60EA /* RNSentryTests.mm in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

#import "RNSentryBreadcrumb.h"
#import "RNSentryReplayBreadcrumbConverter.h"
#import "RNSentryReplay.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import XCTest
import Sentry

final class RNSentryReplayOptions: XCTestCase {

func testOptionsWithoutExperimentalAreIgnored() {
let optionsDict = NSMutableDictionary()
RNSentryReplay.updateOptions(optionsDict)

XCTAssertEqual(optionsDict.count, 0)
}

func testExperimentalOptionsWithoutReplaySampleRatesAreRemoved() {
let optionsDict = (["_experiments": [:]] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

XCTAssertEqual(optionsDict.count, 0)
}

func testReplayOptionsDictContainsAllOptionsKeysWhenSessionSampleRateUsed() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [
"replaysSessionSampleRate": 0.75
]
] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

let experimental = optionsDict["experimental"] as! [String:Any]
let sessionReplay = experimental["sessionReplay"] as! [String:Any]

assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay)
}

func testReplayOptionsDictContainsAllOptionsKeysWhenErrorSampleRateUsed() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [
"replaysOnErrorSampleRate": 0.75
]
] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

let experimental = optionsDict["experimental"] as! [String:Any]
let sessionReplay = experimental["sessionReplay"] as! [String:Any]

assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay)
}

func testReplayOptionsDictContainsAllOptionsKeysWhenErrorAndSessionSampleRatesUsed() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [
"replaysOnErrorSampleRate": 0.75,
"replaysSessionSampleRate": 0.75
]
] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

let experimental = optionsDict["experimental"] as! [String:Any]
let sessionReplay = experimental["sessionReplay"] as! [String:Any]

assertAllDefaultReplayOptionsAreNotNil(replayOptions: sessionReplay)
}

func assertAllDefaultReplayOptionsAreNotNil(replayOptions: [String: Any]) {
XCTAssertEqual(replayOptions.count, 5)
XCTAssertNotNil(replayOptions["sessionSampleRate"])
XCTAssertNotNil(replayOptions["errorSampleRate"])
XCTAssertNotNil(replayOptions["redactAllImages"])
XCTAssertNotNil(replayOptions["redactAllText"])
XCTAssertNotNil(replayOptions["maskedViewClasses"])
}

func testSessionSampleRate() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [ "replaysSessionSampleRate": 0.75 ]
] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

let actualOptions = try! Options(dict: optionsDict as! [String: Any])
XCTAssertEqual(actualOptions.experimental.sessionReplay.sessionSampleRate, 0.75)
}

func testOnErrorSampleRate() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [ "replaysOnErrorSampleRate": 0.75 ]
] as NSDictionary).mutableCopy() as! NSMutableDictionary
RNSentryReplay.updateOptions(optionsDict)

let actualOptions = try! Options(dict: optionsDict as! [String: Any])
XCTAssertEqual(actualOptions.experimental.sessionReplay.onErrorSampleRate, 0.75)
}

func testMaskAllVectors() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [ "replaysOnErrorSampleRate": 0.75 ],
"mobileReplayOptions": [ "maskAllVectors": true ]
] as NSDictionary).mutableCopy() as! NSMutableDictionary

RNSentryReplay.updateOptions(optionsDict)

XCTAssertEqual(optionsDict.count, 3)

let experimental = optionsDict["experimental"] as! [String:Any]
let sessionReplay = experimental["sessionReplay"] as! [String:Any]

let maskedViewClasses = sessionReplay["maskedViewClasses"] as! [String]
XCTAssertEqual(maskedViewClasses.count, 1)
XCTAssertEqual(maskedViewClasses[0], "RNSVGSvgView")

let actualOptions = try! Options(dict: optionsDict as! [String: Any])
XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 0)
}

func testMaskAllImages() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [ "replaysOnErrorSampleRate": 0.75 ],
"mobileReplayOptions": [ "maskAllImages": true ]
] as NSDictionary).mutableCopy() as! NSMutableDictionary

RNSentryReplay.updateOptions(optionsDict)

let actualOptions = try! Options(dict: optionsDict as! [String: Any])

XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllImages, true)
XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 1)
XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0])
XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTImageView")!))
}

func testMaskAllText() {
let optionsDict = ([
"dsn": "https://[email protected]/1234567",
"_experiments": [ "replaysOnErrorSampleRate": 0.75 ],
"mobileReplayOptions": [ "maskAllText": true ]
] as NSDictionary).mutableCopy() as! NSMutableDictionary

RNSentryReplay.updateOptions(optionsDict)

let actualOptions = try! Options(dict: optionsDict as! [String: Any])

XCTAssertEqual(actualOptions.experimental.sessionReplay.maskAllText, true)
XCTAssertEqual(actualOptions.experimental.sessionReplay.maskedViewClasses.count, 2)
XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[0])
XCTAssertNotNil(actualOptions.experimental.sessionReplay.maskedViewClasses[1])
XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[0]), ObjectIdentifier(NSClassFromString("RCTTextView")!))
XCTAssertEqual(ObjectIdentifier(actualOptions.experimental.sessionReplay.maskedViewClasses[1]), ObjectIdentifier(NSClassFromString("RCTParagraphComponentView")!))
}

}
30 changes: 9 additions & 21 deletions packages/core/ios/RNSentryReplay.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,40 +30,28 @@ + (void)updateOptions:(NSMutableDictionary *)options
@"errorSampleRate" : experiments[@"replaysOnErrorSampleRate"] ?: [NSNull null],
@"redactAllImages" : replayOptions[@"maskAllImages"] ?: [NSNull null],
@"redactAllText" : replayOptions[@"maskAllText"] ?: [NSNull null],
@"maskedViewClasses" : [RNSentryReplay getReplayRNRedactClasses:replayOptions],
}
}
forKey:@"experimental"];

[RNSentryReplay addReplayRNRedactClasses:replayOptions];
}

+ (void)addReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions
+ (NSArray *_Nonnull)getReplayRNRedactClasses:(NSDictionary *_Nullable)replayOptions
{
NSMutableArray *_Nonnull classesToRedact = [[NSMutableArray alloc] init];

if ([replayOptions[@"maskAllVectors"] boolValue] == YES) {
Class _Nullable maybeRNSVGViewClass = NSClassFromString(@"RNSVGSvgView");
if (maybeRNSVGViewClass != nil) {
[classesToRedact addObject:maybeRNSVGViewClass];
}
[classesToRedact addObject:@"RNSVGSvgView"];
}
if ([replayOptions[@"maskAllImages"] boolValue] == YES) {
Class _Nullable maybeRCTImageClass = NSClassFromString(@"RCTImageView");
if (maybeRCTImageClass != nil) {
[classesToRedact addObject:maybeRCTImageClass];
}
[classesToRedact addObject:@"RCTImageView"];
}
if ([replayOptions[@"maskAllText"] boolValue] == YES) {
Class _Nullable maybeRCTTextClass = NSClassFromString(@"RCTTextView");
if (maybeRCTTextClass != nil) {
[classesToRedact addObject:maybeRCTTextClass];
}
Class _Nullable maybeRCTParagraphComponentViewClass
= NSClassFromString(@"RCTParagraphComponentView");
if (maybeRCTParagraphComponentViewClass != nil) {
[classesToRedact addObject:maybeRCTParagraphComponentViewClass];
}
[classesToRedact addObject:@"RCTTextView"];
[classesToRedact addObject:@"RCTParagraphComponentView"];
}
[PrivateSentrySDKOnly addReplayRedactClasses:classesToRedact];

return classesToRedact;
}

+ (void)postInit
Expand Down

0 comments on commit b4e79be

Please sign in to comment.