proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
import Foundation
import UIKit
import CoreLocation

struct Proof: Identifiable {
    let id: UUID
    let fileName: String
    let hash: String
    let createdAt: Date
    let fileSize: Int64
    let mimeType: String
    var isVerified: Bool

    // Optional metadata - Using UniFFI types directly
    let location: LocationData?
    let deviceInfo: DeviceData?
    let networkInfo: NetworkData?
    let signature: String?
    let signedBy: String?

    // Image data (not persisted)
    var imageData: Data?

    var thumbnail: UIImage? {
        guard let data = imageData else { return nil }
        return UIImage(data: data)?.thumbnailImage(targetSize: CGSize(width: 60, height: 60))
    }

    var fullImage: UIImage? {
        guard let data = imageData else { return nil }
        return UIImage(data: data)
    }

    var formattedDate: String {
        let formatter = DateFormatter()
        formatter.dateStyle = .medium
        formatter.timeStyle = .short
        return formatter.string(from: createdAt)
    }

    init(id: UUID = UUID(),
         fileName: String,
         hash: String,
         createdAt: Date = Date(),
         fileSize: Int64,
         mimeType: String = "image/jpeg",
         isVerified: Bool = false,
         location: LocationData? = nil,
         deviceInfo: DeviceData? = nil,
         networkInfo: NetworkData? = nil,
         signature: String? = nil,
         signedBy: String? = nil,
         imageData: Data? = nil) {
        self.id = id
        self.fileName = fileName
        self.hash = hash
        self.createdAt = createdAt
        self.fileSize = fileSize
        self.mimeType = mimeType
        self.isVerified = isVerified
        self.location = location
        self.deviceInfo = deviceInfo
        self.networkInfo = networkInfo
        self.signature = signature
        self.signedBy = signedBy
        self.imageData = imageData
    }

    func exportData() -> Data {
        var exportDict: [String: Any] = [
            "id": id.uuidString,
            "fileName": fileName,
            "hash": hash,
            "createdAt": createdAt.timeIntervalSince1970,
            "fileSize": fileSize,
            "mimeType": mimeType,
            "isVerified": isVerified
        ]

        if let location = location {
            var locationDict: [String: Any] = [
                "latitude": location.latitude,
                "longitude": location.longitude
            ]
            if let altitude = location.altitude {
                locationDict["altitude"] = altitude
            }
            if let accuracy = location.accuracy {
                locationDict["accuracy"] = accuracy
            }
            if let provider = location.provider {
                locationDict["provider"] = provider
            }
            exportDict["location"] = locationDict
        }

        if let deviceInfo = deviceInfo {
            var deviceDict: [String: Any] = [
                "manufacturer": deviceInfo.manufacturer,
                "model": deviceInfo.model,
                "osVersion": deviceInfo.osVersion
            ]
            if let deviceId = deviceInfo.deviceId {
                deviceDict["deviceId"] = deviceId
            }
            exportDict["deviceInfo"] = deviceDict
        }

        if let networkInfo = networkInfo {
            var networkDict: [String: Any] = [
                "networkType": networkInfo.networkType
            ]
            if let wifiSsid = networkInfo.wifiSsid {
                networkDict["wifiSsid"] = wifiSsid
            }
            if let cellInfo = networkInfo.cellInfo {
                var cellDict: [String: Any] = [
                    "carrier": cellInfo.carrier
                ]
                if let cellId = cellInfo.cellId {
                    cellDict["cellId"] = cellId
                }
                if let lac = cellInfo.lac {
                    cellDict["lac"] = lac
                }
                networkDict["cellInfo"] = cellDict
            }
            exportDict["networkInfo"] = networkDict
        }

        if let signature = signature {
            exportDict["signature"] = signature
        }

        if let signedBy = signedBy {
            exportDict["signedBy"] = signedBy
        }

        return try! JSONSerialization.data(withJSONObject: exportDict, options: .prettyPrinted)
    }
}

// MARK: - UIImage Extension
extension UIImage {
    func thumbnailImage(targetSize: CGSize) -> UIImage? {
        let widthRatio = targetSize.width / size.width
        let heightRatio = targetSize.height / size.height
        let ratio = max(widthRatio, heightRatio)

        let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
        let rect = CGRect(origin: .zero, size: newSize)

        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }
}