krz/domain-dig

an ios app for DNS & SSL analysis

clone: git clone https://gitbay.org/krz/domain-dig.git

v5.0.2: DomainDig/DataResetService.swift · raw

 1import Foundation
 2import Security
 3
 4enum DataResetService {
 5    enum ResetError: LocalizedError {
 6        case missingBundleIdentifier
 7
 8        var errorDescription: String? {
 9            switch self {
10            case .missingBundleIdentifier:
11                "DomainDig could not determine its local storage identifier."
12            }
13        }
14    }
15
16    static func wipeAllLocalData(viewModel: DomainViewModel) async throws {
17        let secretReferences = await MainActor.run {
18            IntegrationService.shared.localSecretReferences() + LocalAPIService.shared.localSecretReferences()
19        }
20
21        try await Task.detached(priority: .userInitiated) {
22            try performPersistentWipe(secretReferences: secretReferences)
23        }.value
24
25        await LookupRuntime.shared.clearCache()
26        await LocalNotificationService.shared.clearAllNotifications()
27        await UsageCreditService.shared.resetForCurrentVersion()
28
29        await MainActor.run {
30            IntegrationService.shared.resetAfterLocalWipe()
31            LocalAPIService.shared.resetAfterLocalWipe()
32            CloudSyncService.shared.resetLocalStateAfterWipe()
33            PurchaseService.shared.resetCachedStateAfterLocalWipe()
34            _ = DomainMonitoringScheduler.shared.syncSchedule()
35        }
36
37        await viewModel.applyLocalDataReset()
38    }
39
40    private nonisolated static func performPersistentWipe(secretReferences: [String]) throws {
41        guard let bundleIdentifier = Bundle.main.bundleIdentifier else {
42            throw ResetError.missingBundleIdentifier
43        }
44
45        for reference in secretReferences {
46            deleteIntegrationSecret(reference: reference)
47        }
48
49        try removeTemporaryFiles()
50
51        let defaults = UserDefaults.standard
52        defaults.removePersistentDomain(forName: bundleIdentifier)
53        defaults.synchronize()
54    }
55
56    private nonisolated static func removeTemporaryFiles() throws {
57        let tempDirectory = FileManager.default.temporaryDirectory
58        let urls = try FileManager.default.contentsOfDirectory(
59            at: tempDirectory,
60            includingPropertiesForKeys: nil,
61            options: [.skipsHiddenFiles]
62        )
63
64        for url in urls {
65            try? FileManager.default.removeItem(at: url)
66        }
67    }
68
69    private nonisolated static func deleteIntegrationSecret(reference: String) {
70        let query: [String: Any] = [
71            kSecClass as String: kSecClassGenericPassword,
72            kSecAttrAccount as String: reference
73        ]
74
75        SecItemDelete(query as CFDictionary)
76    }
77}