RadrootsVerifiedArtifactAccess.swift (4844B)
1 import Foundation 2 3 public enum RadrootsVerifiedArtifactAccessError: Error, Equatable, Sendable { 4 case invalidDescriptor 5 case protectedDataUnavailable 6 case artifactUnavailable 7 case artifactCorrupt 8 case fileSystemFailure 9 } 10 11 extension RadrootsVerifiedArtifactAccessError: LocalizedError { 12 public var errorDescription: String? { 13 switch self { 14 case .invalidDescriptor: "The verified-artifact descriptor is invalid." 15 case .protectedDataUnavailable: "Protected data is unavailable." 16 case .artifactUnavailable: "The verified artifact is unavailable." 17 case .artifactCorrupt: "The verified artifact is corrupt." 18 case .fileSystemFailure: "The verified artifact could not be opened." 19 } 20 } 21 } 22 23 public struct RadrootsVerifiedArtifactDescriptor: Sendable, Equatable, Hashable { 24 public let artifactID: String 25 public let byteSize: UInt64 26 public let mediaType: String 27 public let fileExtension: String 28 public let width: UInt32 29 public let height: UInt32 30 31 public init( 32 artifactID: String, 33 byteSize: UInt64, 34 mediaType: String, 35 width: UInt32, 36 height: UInt32 37 ) throws { 38 let normalizedMediaType = 39 mediaType 40 .trimmingCharacters(in: .whitespacesAndNewlines) 41 .lowercased() 42 guard artifactID.range(of: "^[0-9a-f]{64}$", options: .regularExpression) != nil, 43 let fileExtension = Self.fileExtension(for: normalizedMediaType), 44 byteSize > 0, 45 byteSize <= 512 * 1024 * 1024, 46 width > 0, 47 height > 0, 48 width <= 16_384, 49 height <= 16_384, 50 UInt64(width) * UInt64(height) <= 100_000_000 51 else { 52 throw RadrootsVerifiedArtifactAccessError.invalidDescriptor 53 } 54 self.artifactID = artifactID 55 self.byteSize = byteSize 56 self.mediaType = normalizedMediaType 57 self.fileExtension = fileExtension 58 self.width = width 59 self.height = height 60 } 61 62 fileprivate var filename: String { 63 "\(artifactID).\(fileExtension)" 64 } 65 66 private static func fileExtension(for mediaType: String) -> String? { 67 switch mediaType { 68 case "image/gif": "gif" 69 case "image/jpeg": "jpg" 70 case "image/png": "png" 71 case "image/webp": "webp" 72 default: nil 73 } 74 } 75 } 76 77 public struct RadrootsVerifiedArtifactFile: Sendable, Equatable, CustomDebugStringConvertible { 78 public let descriptor: RadrootsVerifiedArtifactDescriptor 79 public let data: Data 80 81 fileprivate init(descriptor: RadrootsVerifiedArtifactDescriptor, data: Data) { 82 self.descriptor = descriptor 83 self.data = data 84 } 85 86 public var debugDescription: String { 87 "RadrootsVerifiedArtifactFile(artifactID: \(descriptor.artifactID), byteSize: \(descriptor.byteSize), mediaType: \(descriptor.mediaType), data: <redacted>)" 88 } 89 } 90 91 /// Opens only Rust-approved, content-addressed inbound media artifacts. 92 /// 93 /// Rust remains the verification and cache authority. This Apple adapter 94 /// independently rechecks the immutable file and returns only its retained, 95 /// verified bytes to a native renderer. It refuses access while protected data 96 /// is unavailable. 97 public struct RadrootsAppleVerifiedArtifactAccess: Sendable { 98 private let ownerDirectory: URL 99 private let protectedData: RadrootsProtectedDataProvider 100 101 public init( 102 mobileStore: RadrootsAppleMobileStoreConfiguration, 103 protectedData: RadrootsProtectedDataProvider = .available 104 ) { 105 ownerDirectory = mobileStore.ownerDirectory 106 self.protectedData = protectedData 107 } 108 109 public func open(_ descriptor: RadrootsVerifiedArtifactDescriptor) throws 110 -> RadrootsVerifiedArtifactFile 111 { 112 guard protectedData.currentState() == .available else { 113 throw RadrootsVerifiedArtifactAccessError.protectedDataUnavailable 114 } 115 do { 116 let data = try RadrootsGovernedFileReader.read( 117 root: ownerDirectory, 118 relativePath: "inbound_media.v1/\(descriptor.filename)", 119 maximumBytes: Int(descriptor.byteSize) 120 ) 121 guard UInt64(data.count) == descriptor.byteSize else { 122 throw RadrootsVerifiedArtifactAccessError.artifactCorrupt 123 } 124 guard RadrootsAppleFileDigest.sha256(data) == descriptor.artifactID else { 125 throw RadrootsVerifiedArtifactAccessError.artifactCorrupt 126 } 127 return RadrootsVerifiedArtifactFile(descriptor: descriptor, data: data) 128 } catch let error as RadrootsVerifiedArtifactAccessError { 129 throw error 130 } catch RadrootsGovernedFileReadError.unavailable { 131 throw RadrootsVerifiedArtifactAccessError.artifactUnavailable 132 } catch is RadrootsGovernedFileReadError { 133 throw RadrootsVerifiedArtifactAccessError.artifactCorrupt 134 } catch { 135 throw RadrootsVerifiedArtifactAccessError.fileSystemFailure 136 } 137 } 138 139 public func revalidate(_ artifact: RadrootsVerifiedArtifactFile) throws -> Bool { 140 try open(artifact.descriptor) == artifact 141 } 142 }