vOOice/VoiceInk/Services/Obfuscator.swift

63 lines
2.2 KiB
Swift

import Foundation
import IOKit
/// Simple utility to obfuscate sensitive data stored in UserDefaults
struct Obfuscator {
/// Encodes a string using Base64 with a device-specific salt
static func encode(_ string: String, salt: String) -> String {
let salted = salt + string + salt
let data = Data(salted.utf8)
return data.base64EncodedString()
}
/// Decodes a Base64 string using a device-specific salt
static func decode(_ base64: String, salt: String) -> String? {
guard let data = Data(base64Encoded: base64),
let salted = String(data: data, encoding: .utf8) else {
return nil
}
// Remove the salt from both ends
guard salted.hasPrefix(salt), salted.hasSuffix(salt) else {
return nil
}
return String(salted.dropFirst(salt.count).dropLast(salt.count))
}
/// Gets a device-specific identifier to use as salt
/// Uses the same logic as PolarService for consistency
static func getDeviceIdentifier() -> String {
// Try to get Mac serial number first
if let serialNumber = getMacSerialNumber() {
return serialNumber
}
// Fallback to stored UUID
let defaults = UserDefaults.standard
if let storedId = defaults.string(forKey: "VoiceInkDeviceIdentifier") {
return storedId
}
// Create and store new UUID
let newId = UUID().uuidString
defaults.set(newId, forKey: "VoiceInkDeviceIdentifier")
return newId
}
/// Try to get the Mac serial number
private static func getMacSerialNumber() -> String? {
let platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
if platformExpert == 0 { return nil }
defer { IOObjectRelease(platformExpert) }
if let serialNumber = IORegistryEntryCreateCFProperty(platformExpert, "IOPlatformSerialNumber" as CFString, kCFAllocatorDefault, 0) {
return (serialNumber.takeRetainedValue() as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
}
return nil
}
}