TeraPublicDisclosureTests.swift (4429B)
1 import ImageIO 2 @testable import TeraApp 3 import UIKit 4 import UniformTypeIdentifiers 5 import XCTest 6 7 @MainActor 8 final class TeraPublicDisclosureTests: XCTestCase { 9 func testCameraAndLibraryStripSensitiveMetadataBeforeCreatingPublicMedia() async throws { 10 let source = try taggedImage() 11 let sourceProperties = try properties(source) 12 XCTAssertNotNil(sourceProperties[kCGImagePropertyGPSDictionary], "The fixture must actually contain GPS") 13 XCTAssertNotNil(sourceProperties[kCGImagePropertyTIFFDictionary]) 14 for camera in [false, true] { 15 let fixture = try OfflineMediaFixture(image: source, filename: "tagged.jpg", mediaType: "image/jpeg") 16 defer { fixture.remove() } 17 let coordinator = fixture.coordinator() 18 let photos = try await camera ? [coordinator.captureImage()] : coordinator.importImages(limit: 1) 19 let photo = try XCTUnwrap(photos.first) 20 let bytes = try Data(contentsOf: fixture.roots.stagedBlobsRoot.appendingPathComponent(photo.sha256)) 21 let output = try properties(bytes) 22 XCTAssertNil(output[kCGImagePropertyGPSDictionary]) 23 XCTAssertNil(output[kCGImagePropertyTIFFDictionary]) 24 XCTAssertNil(output[kCGImagePropertyIPTCDictionary]) 25 let exif = output[kCGImagePropertyExifDictionary] as? [CFString: Any] ?? [:] 26 XCTAssertNil(exif[kCGImagePropertyExifUserComment]) 27 XCTAssertNil(bytes.range(of: Data("C117_PRIVATE_CAMERA".utf8))) 28 XCTAssertNil(photo.remoteURL, "Local intake does not upload or publish") 29 XCTAssertEqual(photo.alt, "") 30 XCTAssertEqual(try Data(contentsOf: fixture.roots.cacheRoot.appendingPathComponent("tagged.jpg")), source) 31 let transfers = await fixture.transfer.enqueueCount 32 XCTAssertEqual(transfers, 0) 33 } 34 } 35 36 func testLocationIsAbsentByDefaultAndOnlyManualTextSurvivesSaveAndRestart() async throws { 37 let fixture = try OfflineMediaFixture() 38 defer { fixture.remove() } 39 let client = TeraRuntimeClient.production() 40 let signer = ComposerForbiddenSigner() 41 let configuration = fixture.configuration(signer) 42 let snapshot = try await client.start(configuration: configuration) 43 var saved: [TeraComposerDraft] = [] 44 for type in TeraAddCommandType.allCases { 45 let store = TeraAddStore(runtimeClient: client, initialType: type) 46 store.configure(snapshot: snapshot) 47 await store.start() 48 XCTAssertNil(store.form.location) 49 store.updateForm(\.content, "local editing") 50 if type == .createEvent || type == .createFoodAvailability { 51 store.updateForm(\.location, "North side of the public market") 52 } 53 await store.save() 54 let draft = try XCTUnwrap(store.savedComposer) 55 XCTAssertEqual(draft.form.location, store.form.location) 56 saved.append(draft) 57 store.stop() 58 } 59 _ = try await client.stop() 60 _ = try await client.start(configuration: configuration) 61 for draft in saved { 62 let restored = try await client.loadComposer(scope: draft.scope, id: draft.id) 63 XCTAssertEqual(restored, draft) 64 } 65 let signs = await signer.requests 66 XCTAssertEqual(signs, 0) 67 _ = try await client.stop() 68 } 69 70 private func properties(_ data: Data) throws -> [CFString: Any] { 71 let source = try XCTUnwrap(CGImageSourceCreateWithData(data as CFData, nil)) 72 return try XCTUnwrap(CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any]) 73 } 74 75 private func taggedImage() throws -> Data { 76 let image = UIGraphicsImageRenderer(size: CGSize(width: 2, height: 2)).image { context in 77 UIColor.green.setFill() 78 context.fill(CGRect(x: 0, y: 0, width: 2, height: 2)) 79 } 80 let output = NSMutableData() 81 let destination = try XCTUnwrap(CGImageDestinationCreateWithData(output, UTType.jpeg.identifier as CFString, 1, nil)) 82 let properties: [CFString: Any] = [ 83 kCGImagePropertyGPSDictionary: [kCGImagePropertyGPSLatitude: 12.3456, kCGImagePropertyGPSLatitudeRef: "N"], 84 kCGImagePropertyTIFFDictionary: [kCGImagePropertyTIFFMake: "C117_PRIVATE_CAMERA"], 85 kCGImagePropertyExifDictionary: [kCGImagePropertyExifUserComment: "C117_PRIVATE_CAMERA"], 86 kCGImagePropertyIPTCDictionary: [kCGImagePropertyIPTCCaptionAbstract: "C117_PRIVATE_CAMERA"], 87 ] 88 try CGImageDestinationAddImage(destination, XCTUnwrap(image.cgImage), properties as CFDictionary) 89 XCTAssertTrue(CGImageDestinationFinalize(destination)) 90 return output as Data 91 } 92 }