Skip to content

Commit d06a4db

Browse files
fix: Add masking for PDFView (#5766)
Co-authored-by: Philipp Hofmann <[email protected]>
1 parent 50bcfb9 commit d06a4db

File tree

8 files changed

+152
-22
lines changed

8 files changed

+152
-22
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Fixes
66

7+
- Add support for PDFKit views in session replay (#5750)
78
- Fix Infinite Session Replay Processing Loop (#5765)
89
- Fix memory leak in SessionReplayIntegration (#5770)
910
- Fix reporting of energy used while profiling (#5768)

Samples/iOS-Swift/iOS-Swift/Base.lproj/Main.storyboard

Lines changed: 45 additions & 20 deletions
Large diffs are not rendered by default.
Binary file not shown.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import PDFKit
2+
3+
class SentryPDFViewController: UIViewController {
4+
override func viewDidLoad() {
5+
super.viewDidLoad()
6+
7+
let pdfView = PDFView()
8+
view.addSubview(pdfView)
9+
10+
pdfView.translatesAutoresizingMaskIntoConstraints = false
11+
NSLayoutConstraint.activate([
12+
pdfView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
13+
pdfView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
14+
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
15+
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
16+
])
17+
18+
guard let fileUrl = Bundle.main.url(forResource: "ProjectProposal", withExtension: "pdf"),
19+
let document = PDFDocument(url: fileUrl) else {
20+
preconditionFailure("Failed to load PDF document from bundle.")
21+
}
22+
pdfView.document = document
23+
}
24+
}

Sources/Swift/Core/Tools/ViewCapture/SentryUIRedactBuilder.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Foundation
44
import ObjectiveC.NSObjCRuntime
55
import UIKit
66
#if os(iOS)
7+
import PDFKit
78
import WebKit
89
#endif
910

@@ -57,7 +58,7 @@ final class SentryUIRedactBuilder {
5758
}
5859

5960
#if os(iOS)
60-
redactClasses += [ WKWebView.self ]
61+
redactClasses += [ PDFView.self, WKWebView.self ]
6162

6263
redactClasses += [
6364
// If we try to use 'UIWebView.self' it will not compile for macCatalyst, but the class does exists.

Tests/SentryTests/ViewCapture/SentryUIRedactBuilderTests.swift

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#if os(iOS)
22
import Foundation
3+
import PDFKit
34
import SafariServices
45
@testable import Sentry
56
import SentryTestUtils
@@ -463,7 +464,7 @@ class SentryUIRedactBuilderTests: XCTestCase {
463464
func testRedactList() {
464465
let expectedList = ["_TtCOCV7SwiftUI11DisplayList11ViewUpdater8Platform13CGDrawingView",
465466
"_TtC7SwiftUIP33_A34643117F00277B93DEBAB70EC0697122_UIShapeHitTestingView",
466-
"SwiftUI._UIGraphicsView", "SwiftUI.ImageLayer", "UIWebView", "SFSafariView", "UILabel", "UITextView", "UITextField", "WKWebView"
467+
"SwiftUI._UIGraphicsView", "SwiftUI.ImageLayer", "UIWebView", "SFSafariView", "UILabel", "UITextView", "UITextField", "WKWebView", "PDFView"
467468
].compactMap { NSClassFromString($0) }
468469

469470
let sut = getSut()
@@ -573,6 +574,70 @@ class SentryUIRedactBuilderTests: XCTestCase {
573574
}
574575
#endif
575576
}
577+
578+
func testRedactPDFView() throws {
579+
// -- Arrange --
580+
let sut = getSut()
581+
let pdfView = PDFView(frame: CGRect(x: 20, y: 20, width: 40, height: 40))
582+
rootView.addSubview(pdfView)
583+
584+
// -- Act --
585+
let result = sut.redactRegionsFor(view: rootView)
586+
587+
// -- Assert --
588+
// Root View
589+
// └ PDFView (Public API)
590+
// └ PDFScrollView (Private API)
591+
XCTAssertEqual(result.count, 2)
592+
let pdfRegion = try XCTUnwrap(result.element(at: 0))
593+
XCTAssertEqual(pdfRegion.size, CGSize(width: 40, height: 40))
594+
XCTAssertEqual(pdfRegion.type, .redact)
595+
XCTAssertEqual(pdfRegion.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))
596+
XCTAssertNil(pdfRegion.color)
597+
598+
let pdfScrollViewRegion = try XCTUnwrap(result.element(at: 1))
599+
XCTAssertEqual(pdfScrollViewRegion.size, CGSize(width: 40, height: 40))
600+
XCTAssertEqual(pdfScrollViewRegion.type, .redact)
601+
XCTAssertEqual(pdfScrollViewRegion.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))
602+
XCTAssertNil(pdfScrollViewRegion.color)
603+
}
604+
605+
func testRedactPDFViewEvenWithMaskingDisabled() throws {
606+
// -- Arrange --
607+
// PDFView should always be redacted for security reasons,
608+
// regardless of maskAllText and maskAllImages settings
609+
let sut = getSut(TestRedactOptions(maskAllText: false, maskAllImages: false))
610+
let pdfView = PDFView(frame: CGRect(x: 20, y: 20, width: 40, height: 40))
611+
rootView.addSubview(pdfView)
612+
613+
// -- Act --
614+
let result = sut.redactRegionsFor(view: rootView)
615+
616+
// -- Assert --
617+
// Root View
618+
// └ PDFView (Public API)
619+
// └ PDFScrollView (Private API)
620+
XCTAssertEqual(result.count, 2)
621+
let pdfRegion = try XCTUnwrap(result.element(at: 0))
622+
XCTAssertEqual(pdfRegion.size, CGSize(width: 40, height: 40))
623+
XCTAssertEqual(pdfRegion.type, .redact)
624+
XCTAssertEqual(pdfRegion.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))
625+
XCTAssertNil(pdfRegion.color)
626+
627+
let pdfScrollViewRegion = try XCTUnwrap(result.element(at: 1))
628+
XCTAssertEqual(pdfScrollViewRegion.size, CGSize(width: 40, height: 40))
629+
XCTAssertEqual(pdfScrollViewRegion.type, .redact)
630+
XCTAssertEqual(pdfScrollViewRegion.transform, CGAffineTransform(a: 1, b: 0, c: 0, d: 1, tx: 20, ty: 20))
631+
XCTAssertNil(pdfScrollViewRegion.color)
632+
}
633+
634+
func testPDFViewInRedactList() {
635+
// -- Arrange --
636+
let sut = getSut()
637+
638+
// -- Act & Assert --
639+
XCTAssertTrue(sut.containsRedactClass(PDFView.self), "PDFView should be in the redact class list")
640+
}
576641
}
577642

578643
#endif

sdk_api.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41693,6 +41693,13 @@
4169341693
"declKind": "Import",
4169441694
"moduleName": "Sentry"
4169541695
},
41696+
{
41697+
"kind": "Import",
41698+
"name": "PDFKit",
41699+
"printedName": "PDFKit",
41700+
"declKind": "Import",
41701+
"moduleName": "Sentry"
41702+
},
4169641703
{
4169741704
"kind": "Import",
4169841705
"name": "Sentry",

sdk_api_V9.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39013,6 +39013,13 @@
3901339013
"declKind": "Import",
3901439014
"moduleName": "Sentry"
3901539015
},
39016+
{
39017+
"kind": "Import",
39018+
"name": "PDFKit",
39019+
"printedName": "PDFKit",
39020+
"declKind": "Import",
39021+
"moduleName": "Sentry"
39022+
},
3901639023
{
3901739024
"kind": "Import",
3901839025
"name": "Sentry",

0 commit comments

Comments
 (0)