Skip to content

Commit 31ed529

Browse files
authored
Merge pull request #5419 from woocommerce/issue/4137-escape-html-receipt
[Mobile Payments] Remove html tags from receipt generation
2 parents 0d3a82c + 7c2f860 commit 31ed529

File tree

4 files changed

+113
-9
lines changed

4 files changed

+113
-9
lines changed

Hardware/Hardware.xcodeproj/project.pbxproj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/* Begin PBXBuildFile section */
1010
030338102705F7D400764131 /* ReceiptTotalLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0303380F2705F7D400764131 /* ReceiptTotalLine.swift */; };
1111
311889EB2653286B0080AEA2 /* PaymentIntentMetadataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 311889EA2653286B0080AEA2 /* PaymentIntentMetadataTests.swift */; };
12+
55CD4BB4273E617C007686D3 /* ReceiptRendererTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55CD4BB3273E617C007686D3 /* ReceiptRendererTest.swift */; };
1213
5A747BE9FA06EC8752A35752 /* Pods_HardwareTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1DC5B6141B8184FAC29B0A4 /* Pods_HardwareTests.framework */; };
1314
8FFAA245E257B9EB98E2FCBD /* Pods_SampleReceiptPrinter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AFA997D6786C67B0A061854 /* Pods_SampleReceiptPrinter.framework */; };
1415
C5D2CB7D21CEE28FEBF18BF6 /* Pods_Hardware.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E9F0AC202B287C1221EA2C99 /* Pods_Hardware.framework */; };
@@ -134,6 +135,7 @@
134135
311889EA2653286B0080AEA2 /* PaymentIntentMetadataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentIntentMetadataTests.swift; sourceTree = "<group>"; };
135136
3CF9348BADD5E0518080A61A /* Pods-Hardware.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Hardware.debug.xcconfig"; path = "Target Support Files/Pods-Hardware/Pods-Hardware.debug.xcconfig"; sourceTree = "<group>"; };
136137
47BDD50287B7B0CF8D769BFC /* Pods-PrinterPlayground.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PrinterPlayground.release-alpha.xcconfig"; path = "Target Support Files/Pods-PrinterPlayground/Pods-PrinterPlayground.release-alpha.xcconfig"; sourceTree = "<group>"; };
138+
55CD4BB3273E617C007686D3 /* ReceiptRendererTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptRendererTest.swift; sourceTree = "<group>"; };
137139
9726331F55A9621F2F887E13 /* Pods-Hardware.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Hardware.release.xcconfig"; path = "Target Support Files/Pods-Hardware/Pods-Hardware.release.xcconfig"; sourceTree = "<group>"; };
138140
AE60F16D43C20AD4523A61A5 /* Pods-SampleReceiptPrinter.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SampleReceiptPrinter.debug.xcconfig"; path = "Target Support Files/Pods-SampleReceiptPrinter/Pods-SampleReceiptPrinter.debug.xcconfig"; sourceTree = "<group>"; };
139141
B1DC5B6141B8184FAC29B0A4 /* Pods_HardwareTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HardwareTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -258,6 +260,14 @@
258260
/* End PBXFrameworksBuildPhase section */
259261

260262
/* Begin PBXGroup section */
263+
55CD4BB2273E6159007686D3 /* AirPrintReceipt */ = {
264+
isa = PBXGroup;
265+
children = (
266+
55CD4BB3273E617C007686D3 /* ReceiptRendererTest.swift */,
267+
);
268+
path = AirPrintReceipt;
269+
sourceTree = "<group>";
270+
};
261271
ADED522B787D093F499BD540 /* Pods */ = {
262272
isa = PBXGroup;
263273
children = (
@@ -351,6 +361,7 @@
351361
D88FDB0C25DD216B00CB0DBD /* HardwareTests */ = {
352362
isa = PBXGroup;
353363
children = (
364+
55CD4BB2273E6159007686D3 /* AirPrintReceipt */,
354365
D845BDF3262DD65D00A3E40F /* Mocks */,
355366
D88FDB0F25DD216B00CB0DBD /* Info.plist */,
356367
D892F21325E3F67A001D7134 /* CardReaderTests.swift */,
@@ -566,6 +577,7 @@
566577
};
567578
D88FDB0725DD216B00CB0DBD = {
568579
CreatedOnToolsVersion = 12.4;
580+
LastSwiftMigration = 1310;
569581
};
570582
E1CFC14A2643E9EE0089F86F = {
571583
CreatedOnToolsVersion = 12.4;
@@ -797,6 +809,7 @@
797809
D81AE85E25E6A89F00D9CFD3 /* StripeCardReaderCacheTests.swift in Sources */,
798810
D892F21425E3F67A001D7134 /* CardReaderTests.swift in Sources */,
799811
D854FC26260A6B5800A219CD /* ErrorCodesTests.swift in Sources */,
812+
55CD4BB4273E617C007686D3 /* ReceiptRendererTest.swift in Sources */,
800813
D892F21025E3F4C0001D7134 /* MockStripeCardReader.swift in Sources */,
801814
D88303DB25E450E700C877F9 /* PaymentIntentTests.swift in Sources */,
802815
D845BE03262DDBF500A3E40F /* CardBrandTests.swift in Sources */,
@@ -1019,6 +1032,7 @@
10191032
baseConfigurationReference = 1CC96A71F2937BCB7432766F /* Pods-HardwareTests.debug.xcconfig */;
10201033
buildSettings = {
10211034
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}";
1035+
CLANG_ENABLE_MODULES = YES;
10221036
CODE_SIGN_IDENTITY = "iPhone Developer";
10231037
CODE_SIGN_STYLE = Automatic;
10241038
DEVELOPMENT_TEAM = PZYM8XX95Q;
@@ -1030,6 +1044,7 @@
10301044
);
10311045
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.Hardware.HardwareTests;
10321046
PRODUCT_NAME = "$(TARGET_NAME)";
1047+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
10331048
SWIFT_VERSION = 5.0;
10341049
TARGETED_DEVICE_FAMILY = "1,2";
10351050
};
@@ -1040,6 +1055,7 @@
10401055
baseConfigurationReference = C61D1642BE09D1A1AD6AA9FA /* Pods-HardwareTests.release.xcconfig */;
10411056
buildSettings = {
10421057
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}";
1058+
CLANG_ENABLE_MODULES = YES;
10431059
CODE_SIGN_IDENTITY = "iPhone Developer";
10441060
CODE_SIGN_STYLE = Automatic;
10451061
DEVELOPMENT_TEAM = PZYM8XX95Q;
@@ -1147,6 +1163,7 @@
11471163
baseConfigurationReference = DB2B86965868C0EC25910D7D /* Pods-HardwareTests.release-alpha.xcconfig */;
11481164
buildSettings = {
11491165
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}";
1166+
CLANG_ENABLE_MODULES = YES;
11501167
CODE_SIGN_IDENTITY = "iPhone Developer";
11511168
CODE_SIGN_STYLE = Automatic;
11521169
DEVELOPMENT_TEAM = PZYM8XX95Q;

Hardware/Hardware/Printer/AirPrintReceipt/ReceiptRenderer.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ private extension ReceiptRenderer {
110110
private func summaryTable() -> String {
111111
var summaryContent = "<table>"
112112
for line in content.lineItems {
113-
summaryContent += "<tr><td>\(line.title) × \(line.quantity)</td><td>\(line.amount) \(content.parameters.currency.uppercased())</td></tr>"
113+
let stripedTitle = line.title.htmlStripped()
114+
summaryContent += "<tr><td>\(stripedTitle) × \(line.quantity)</td><td>\(line.amount) \(content.parameters.currency.uppercased())</td></tr>"
114115
}
115116
summaryContent += totalRows()
116117
summaryContent += "</table>"
@@ -158,9 +159,9 @@ private extension ReceiptRenderer {
158159
/// are required in the US.
159160
/// https://stripe.com/docs/terminal/checkout/receipts#custom
160161
return """
161-
\(Localization.applicationName): \(emv.applicationPreferredName)<br/>
162-
\(Localization.aid): \(emv.dedicatedFileName)
163-
"""
162+
\(Localization.applicationName): \(emv.applicationPreferredName.htmlStripped())<br/>
163+
\(Localization.aid): \(emv.dedicatedFileName.htmlStripped())
164+
"""
164165
}
165166

166167
private func cardIconCSS() -> String {
@@ -250,3 +251,19 @@ private extension ReceiptRenderer {
250251
)
251252
}
252253
}
254+
255+
private extension String {
256+
func htmlStripped() -> String {
257+
let data = Data(utf8)
258+
do {
259+
return try NSAttributedString(
260+
data: data,
261+
options: [.documentType: NSAttributedString.DocumentType.html],
262+
documentAttributes: nil
263+
).string
264+
} catch {
265+
DDLogError("Failed to remove HTML from \(self): \(error.localizedDescription)")
266+
return self
267+
}
268+
}
269+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import XCTest
2+
@testable import Hardware
3+
import StripeTerminal
4+
import Foundation
5+
import CryptoKit
6+
7+
final class ReceiptRendererTest: XCTestCase {
8+
func test_TextWithoutHtmlSymbols() {
9+
let expectedResultWithoutHtmlSymbolsMd5Description = "MD5 digest: 532a92e85527596a692b4b9ee7c978a5"
10+
let content = generateReceiptContent()
11+
12+
let renderer = ReceiptRenderer(content: content)
13+
14+
XCTAssertEqual(
15+
Insecure.MD5.hash(data: renderer.htmlContent().data(using: .utf8)!).description,
16+
expectedResultWithoutHtmlSymbolsMd5Description
17+
)
18+
}
19+
20+
func test_TextWithHtmlSymbols() {
21+
let expectedResultWithHtmlSymbolsMd5Description = "MD5 digest: 034ae681824b18c473c9ca9ad69a06bb"
22+
let stringWithHtml = "<tt><table></table></footer>"
23+
let content = generateReceiptContent(stringToAppend: stringWithHtml)
24+
25+
let renderer = ReceiptRenderer(content: content)
26+
27+
print(renderer.htmlContent())
28+
29+
XCTAssertEqual(
30+
Insecure.MD5.hash(data: renderer.htmlContent().data(using: .utf8)!).description,
31+
expectedResultWithHtmlSymbolsMd5Description
32+
)
33+
}
34+
}
35+
36+
private extension ReceiptRendererTest {
37+
func generateReceiptContent(stringToAppend: String = "") -> ReceiptContent {
38+
ReceiptContent(
39+
parameters: CardPresentReceiptParameters(
40+
amount: 1,
41+
formattedAmount: "1",
42+
currency: "USD",
43+
date: .init(),
44+
storeName: "Test Store",
45+
cardDetails: .init(
46+
last4: "1234",
47+
expMonth: 12,
48+
expYear: 26,
49+
cardholderName: "John Smith",
50+
brand: .masterCard,
51+
fingerprint: "fpr*****",
52+
generatedCard: "pm_******",
53+
receipt: .init(
54+
applicationPreferredName: "Stripe Credit\(stringToAppend)",
55+
dedicatedFileName: "A00000000000000\(stringToAppend)",
56+
authorizationResponseCode: "0000",
57+
applicationCryptogram: "XXXXXXXXXXXX",
58+
terminalVerificationResults: "101010101010101010",
59+
transactionStatusInformation: "6800",
60+
accountType: "credit"
61+
),
62+
emvAuthData: "AD*******"),
63+
orderID: 9201
64+
),
65+
lineItems: [ReceiptLineItem(title: "Sample product #1\(stringToAppend)", quantity: "2", amount: "25")],
66+
cartTotals: [ReceiptTotalLine(description: "description", amount: "13")],
67+
orderNote: nil
68+
)
69+
}
70+
}

Yosemite/Yosemite/Stores/ReceiptStore.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,12 +208,12 @@ private extension ReceiptStore {
208208

209209
private extension ReceiptStore {
210210
func fileURL(order: Order) throws -> URL {
211-
return try FileManager.default.url(for: .documentDirectory,
212-
in: .userDomainMask,
213-
appropriateFor: nil,
214-
create: false)
211+
try FileManager.default.url(for: .documentDirectory,
212+
in: .userDomainMask,
213+
appropriateFor: nil,
214+
create: false)
215215
.appendingPathComponent(fileName(order: order))
216-
.appendingPathExtension("plist")
216+
.appendingPathExtension("plist")
217217
}
218218

219219
func fileName(order: Order) -> String {

0 commit comments

Comments
 (0)