mirror of
https://github.com/BigMarc/grammargem.git
synced 2026-10-13 17:01:55 +02:00
- Added LiveMonitor class to scan text areas in the frontmost window for grammar and spelling issues. - Introduced DetectedField struct to represent text areas with issues, including suggestions for corrections. - Implemented functionality to apply corrections and dismiss suggestions. - Added Permissions class to manage Accessibility permissions required for monitoring. - Created SnippetStore for managing text-expansion snippets, including persistence to UserDefaults. - Developed TextCapture class to read and write text from the frontmost application using Accessibility API and clipboard fallback. - Implemented TextFieldScanner to traverse the Accessibility tree and collect editable text elements. - Added TextReplacementCoordinator to orchestrate the text correction process. - Integrated UpdaterManager for handling application updates using Sparkle. - Created comprehensive unit tests for various components, including grammar corrections and entitlement checks.
48 lines
1.8 KiB
Swift
48 lines
1.8 KiB
Swift
import Foundation
|
|
import IOKit
|
|
import CryptoKit
|
|
|
|
/// Derives a stable, privacy-preserving device identifier.
|
|
///
|
|
/// Lemon Squeezy has no hardware fingerprinting of its own, so we build one
|
|
/// (spec §6): take the hardware `IOPlatformUUID`, SHA-256 it, and pass the hash
|
|
/// as the `instance_name` on activation. Same Mac → same instance → a reinstall
|
|
/// doesn't consume a second device slot. The raw UUID never leaves the device;
|
|
/// only its hash is sent.
|
|
enum DeviceFingerprint {
|
|
/// SHA-256 of the hardware platform UUID, hex-encoded. Falls back to a
|
|
/// persisted random ID if IOKit is somehow unavailable.
|
|
static func stableID() -> String {
|
|
if let uuid = platformUUID() {
|
|
let digest = SHA256.hash(data: Data(uuid.utf8))
|
|
return digest.map { String(format: "%02x", $0) }.joined()
|
|
}
|
|
return fallbackID()
|
|
}
|
|
|
|
private static func platformUUID() -> String? {
|
|
let service = IOServiceGetMatchingService(
|
|
kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
|
|
guard service != 0 else { return nil }
|
|
defer { IOObjectRelease(service) }
|
|
|
|
guard let cf = IORegistryEntryCreateCFProperty(
|
|
service, kIOPlatformUUIDKey as CFString, kCFAllocatorDefault, 0)
|
|
else { return nil }
|
|
return cf.takeRetainedValue() as? String
|
|
}
|
|
|
|
/// A friendly, human-readable name for this Mac (for the Devices screen).
|
|
static func deviceName() -> String {
|
|
Host.current().localizedName ?? ProcessInfo.processInfo.hostName
|
|
}
|
|
|
|
private static func fallbackID() -> String {
|
|
let key = "GrammaGem.fallbackDeviceID"
|
|
if let existing = UserDefaults.standard.string(forKey: key) { return existing }
|
|
let id = UUID().uuidString
|
|
UserDefaults.standard.set(id, forKey: key)
|
|
return id
|
|
}
|
|
}
|