From 015172b7194496c3cc710ed142b48221de81c99e Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Sun, 10 Jan 2021 17:40:39 -0800 Subject: [PATCH] Unescape XML entities in notification body --- Metatext.xcodeproj/project.pbxproj | 4 ++ .../NotificationService.swift | 2 +- .../XMLUnescaper.swift | 37 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Notification Service Extension/XMLUnescaper.swift diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index d3c3f74..f50ee0d 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ D059373425AAEA7000754FDF /* CompositionPollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D059373225AAEA7000754FDF /* CompositionPollView.swift */; }; D059373E25AB8D5200754FDF /* CompositionPollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D059373D25AB8D5200754FDF /* CompositionPollOptionView.swift */; }; D059373F25AB8D5200754FDF /* CompositionPollOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D059373D25AB8D5200754FDF /* CompositionPollOptionView.swift */; }; + D059376125ABE2E800754FDF /* XMLUnescaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D059376025ABE2E800754FDF /* XMLUnescaper.swift */; }; D0625E59250F092900502611 /* StatusListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E58250F092900502611 /* StatusListCell.swift */; }; D0625E5D250F0B5C00502611 /* StatusContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */; }; D06BC5E625202AD90079541D /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06BC5E525202AD90079541D /* ProfileViewController.swift */; }; @@ -202,6 +203,7 @@ D05936FE25AA94EA00754FDF /* MarkAttachmentsSensitiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkAttachmentsSensitiveView.swift; sourceTree = ""; }; D059373225AAEA7000754FDF /* CompositionPollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionPollView.swift; sourceTree = ""; }; D059373D25AB8D5200754FDF /* CompositionPollOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompositionPollOptionView.swift; sourceTree = ""; }; + D059376025ABE2E800754FDF /* XMLUnescaper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLUnescaper.swift; sourceTree = ""; }; D0625E58250F092900502611 /* StatusListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusListCell.swift; sourceTree = ""; }; D0625E5C250F0B5C00502611 /* StatusContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentConfiguration.swift; sourceTree = ""; }; D0666A2124C677B400F3F04B /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -563,6 +565,7 @@ D0E5361D24E3EB4D00FB1CE1 /* Info.plist */, D0E5362824E4A06B00FB1CE1 /* Notification Service Extension.entitlements */, D0E5361B24E3EB4D00FB1CE1 /* NotificationService.swift */, + D059376025ABE2E800754FDF /* XMLUnescaper.swift */, ); path = "Notification Service Extension"; sourceTree = ""; @@ -911,6 +914,7 @@ buildActionMask = 2147483647; files = ( D0E5361C24E3EB4D00FB1CE1 /* NotificationService.swift in Sources */, + D059376125ABE2E800754FDF /* XMLUnescaper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Notification Service Extension/NotificationService.swift b/Notification Service Extension/NotificationService.swift index 393fb61..98dafe6 100644 --- a/Notification Service Extension/NotificationService.swift +++ b/Notification Service Extension/NotificationService.swift @@ -32,7 +32,7 @@ final class NotificationService: UNNotificationServiceExtension { } bestAttemptContent.title = pushNotification.title - bestAttemptContent.body = pushNotification.body + bestAttemptContent.body = XMLUnescaper(string: pushNotification.body).unescape() let fileName = pushNotification.icon.lastPathComponent let fileURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(fileName) diff --git a/Notification Service Extension/XMLUnescaper.swift b/Notification Service Extension/XMLUnescaper.swift new file mode 100644 index 0000000..2379a19 --- /dev/null +++ b/Notification Service Extension/XMLUnescaper.swift @@ -0,0 +1,37 @@ +// Copyright © 2021 Metabolist. All rights reserved. + +import Foundation + +final class XMLUnescaper: NSObject { + private let rawString: String + private let parser: XMLParser + private var unescaped = "" + private static let containerTag = "com.metabolist.metatext.container-tag" + private static let openingContainerTag = "<\(containerTag)>" + private static let closingContainerTag = "" + + init(string: String) { + rawString = Self.openingContainerTag + .appending(string) + .appending(Self.closingContainerTag) + parser = XMLParser(data: Data(rawString.utf8)) + + super.init() + + parser.delegate = self + } +} + +extension XMLUnescaper { + func unescape() -> String { + parser.parse() + + return unescaped + } +} + +extension XMLUnescaper: XMLParserDelegate { + func parser(_ parser: XMLParser, foundCharacters string: String) { + unescaped.append(string) + } +}