eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1import Foundation
2import Security
3
4// πŸ€– The full local reset behind SIGN OUT: wipes everything the app persists β€”
5// Keychain identities, thread keys, the home session, UserDefaults, and the
6// on-disk stores β€” so the next launch is a true first run. Signing out of
7// Eleven MEANS clearing this device: the spaces live in the member's Eleven
8// account, and signing back in restores them (the caller pushes a final sync
9// first). Also the reason a plain uninstall isn't a reset: Keychain items
10// survive app deletion on iOS.
11public enum AppReset {
12 public static func wipeAll() {
13 // Whole-service deletes (no account = every item), with and without
14 // the app-family access group β€” matching how the stores write.
15 for service in ["com.lchat.client", "com.lchat.client.threadkeys"] {
16 for withGroup in [true, false] {
17 var query: [String: Any] = [
18 kSecClass as String: kSecClassGenericPassword,
19 kSecAttrService as String: service,
20 kSecUseDataProtectionKeychain as String: true,
21 ]
22 if withGroup {
23 // Same group constant as Keychain/SharedThreadKeys.
24 query[kSecAttrAccessGroup as String] =
25 "J5NDF5PCD8.com.elevenmessenger.messenger.shared"
26 }
27 SecItemDelete(query as CFDictionary)
28 }
29 }
30 if let bundleID = Bundle.main.bundleIdentifier {
31 UserDefaults.standard.removePersistentDomain(forName: bundleID)
32 }
33 let fm = FileManager.default
34 #if os(macOS)
35 // NOT sandboxed on the Mac: the search paths are the user's REAL
36 // Library folders, so only paths that are provably OURS may go β€” the
37 // app's data dir (MessageStore/MacChatsStore both live in
38 // "Application Support/lchat"), its WebKit store (the webviews'
39 // localStorage identities), and its caches. Never the whole folder.
40 for base in fm.urls(for: .applicationSupportDirectory, in: .userDomainMask) {
41 try? fm.removeItem(at: base.appendingPathComponent("lchat"))
42 }
43 if let bundleID = Bundle.main.bundleIdentifier {
44 for base in fm.urls(for: .cachesDirectory, in: .userDomainMask) {
45 try? fm.removeItem(at: base.appendingPathComponent(bundleID))
46 }
47 for base in fm.urls(for: .libraryDirectory, in: .userDomainMask) {
48 try? fm.removeItem(at: base.appendingPathComponent("WebKit/\(bundleID)"))
49 try? fm.removeItem(at: base.appendingPathComponent("HTTPStorages/\(bundleID)"))
50 }
51 }
52 #else
53 // Sandboxed: the search paths are the app's own container β€” wipe wholesale.
54 for dir: FileManager.SearchPathDirectory in [.applicationSupportDirectory,
55 .cachesDirectory, .documentDirectory] {
56 for url in fm.urls(for: dir, in: .userDomainMask) {
57 for item in (try? fm.contentsOfDirectory(at: url,
58 includingPropertiesForKeys: nil)) ?? [] {
59 try? fm.removeItem(at: item)
60 }
61 }
62 }
63 try? fm.removeItem(at: fm.temporaryDirectory)
64 #endif
65 }
66}
67