CryptoPassphrase  Diff

Differences From Artifact [0a36bee6de]:

To Artifact [0072dc8d4f]:


20
21
22
23
24
25
26
27
28
29
30
31
32



33
34
35
36


37
38
39
40
41
42
43
44
45
46
47
48


49
50




51
52

53
54
55
56
57

58
59
60

61
62
63



64
65
66
67
68
69

70
71

72
73
74
75

76
77
78
79

80
81
82
83
84

85
86
87
88
89
90
91


92

93
94
95
96


97
98

99
100
101


102
103
104
105

106
107
108
109


110
111
112
113


114
115

116
117
118
119
120


121
122

123
124
125
126
127


128
129
130
131


132
133


134
135
20
21
22
23
24
25
26






27
28
29
30
31


32
33
34
35
36
37
38
39
40
41
42
43
44

45
46
47

48
49
50
51
52

53
54
55
56
57

58
59
60

61



62
63
64






65


66
67
68
69

70
71
72
73

74
75
76
77
78

79
80





81
82
83

84
85
86


87
88


89



90
91
92
93
94

95
96
97


98
99




100
101


102





103
104

105
106
107
108
109


110
111
112
113
114
115
116
117


118
119
120
121







-
-
-
-
-
-
+
+
+


-
-
+
+











-
+
+

-
+
+
+
+

-
+




-
+


-
+
-
-
-
+
+
+
-
-
-
-
-
-
+
-
-
+



-
+



-
+




-
+

-
-
-
-
-

+
+
-
+


-
-
+
+
-
-
+
-
-
-
+
+



-
+


-
-
+
+
-
-
-
-
+
+
-
-
+
-
-
-
-
-
+
+
-

+



-
-
+
+




+
+
-
-
+
+


 * POSSIBILITY OF SUCH DAMAGE.
 */

import ObjFW
import ObjFWBridge

class SiteStorage: OFObject {
    private typealias Storage =
        OFMutableDictionary<OFString, OFDictionary<OFNumber, AnyObject>>

    private static let lengthField = OFNumber(uInt8: 0)
    private static let legacyField = OFNumber(uInt8: 1)
    private static let keyFileField = OFNumber(uInt8: 2)
    private static let lengthField = NSNumber(value: 0)
    private static let legacyField = NSNumber(value: 1)
    private static let keyFileField = NSNumber(value: 2)

    private var path: OFString
    private var storage: Storage
    private var sites: OFArray<OFString>
    private var storage: [String: [NSNumber: AnyObject]]
    private var sites: [String]

    override init() {
        let fileManager = OFFileManager.default
        let userDataPath = OFSystemInfo.userDataPath!

        if !fileManager.directoryExists(atPath: userDataPath) {
            fileManager.createDirectory(atPath: userDataPath)
        }

        let path = userDataPath.appendingPathComponent(
            OFString(utf8String: "sites.msgpack"))
        var storage: Storage? = nil

        var storage: [String: [NSNumber: AnyObject]]? = nil
        OFException.try({
            storage = OFData(contentsOfFile: path).messagePackValue as? Storage
            let decoded = (OFData(contentsOfFile: path).messagePackValue)
                as? OFDictionary<OFString, OFDictionary<OFNumber, AnyObject>>
            storage =
                (decoded?.nsObject as? [String: [NSNumber: AnyObject]]) ?? [:]
        }, catch: { (OFException) in
            storage = OFMutableDictionary()
            storage = [:]
        })

        self.path = path
        self.storage = storage!
        self.sites = self.storage.allKeys.sorted
        self.sites = self.storage.keys.sorted()
    }

    func sites(withFilter filter: OFString?) -> OFArray<OFString> {
    func sites(withFilter filter: String?) -> [String] {
        // FIXME: We need case folding here, but there is no method for it yet.
        let filter = filter?.lowercase

        return storage.keys.sorted().filter({ (name) in
            if let filter = filter {
                return name.localizedCaseInsensitiveContains(filter)
        return storage.allKeys.sorted.filteredArray({
            (name: Any, index: size_t) -> Bool in
            if filter == nil {
                return true
            }

            }
            let name = name as! OFString
            return name.lowercase.contains(filter!)
            return true
        })
    }

    func hasSite(_ name: OFString) -> Bool {
    func hasSite(_ name: String) -> Bool {
        return (storage[name] != nil)
    }

    func length(forSite name: OFString) -> size_t {
    func length(forSite name: String) -> UInt {
        guard let site = storage[name] else {
            OFInvalidArgumentException().throw()
        }

        return (site[SiteStorage.lengthField] as! OFNumber).sizeValue
        return (site[SiteStorage.lengthField] as! NSNumber).uintValue
    }

    func isLegacy(site name: OFString) -> Bool {
        guard let site = storage[name] else {
            OFInvalidArgumentException().throw()
        }

    func isLegacy(site name: String) -> Bool {
        guard let site = storage[name] else { return false }
        return (site[SiteStorage.legacyField] as! OFNumber).boolValue
        return (site[SiteStorage.legacyField] as! NSNumber).boolValue
    }

    func keyFile(forSite name: OFString) -> OFString? {
        guard let site = storage[name] else {
    func keyFile(forSite name: String) -> String? {
        guard let site = storage[name] else { return nil }
            OFInvalidArgumentException().throw()
        }


        let keyFile = site[SiteStorage.keyFileField]
        if keyFile is OFNull {
        guard let keyFile = site[SiteStorage.keyFileField], !(keyFile is NSNull)
        else {
            return nil
        }

        return keyFile as? OFString
        return keyFile as? String
    }

    func setSite(_ name: OFString, length: size_t, legacy: Bool,
                 keyFile: OFString?) {
    func setSite(_ name: String, length: UInt, isLegacy: Bool,
                 keyFile: String?) {
        let siteDictionary = OFMutableDictionary<OFNumber, AnyObject>()

        siteDictionary.setObject(OFNumber(size: length),
                                 forKey: SiteStorage.lengthField)
        var siteDictionary: [NSNumber: AnyObject] = [
            SiteStorage.lengthField: NSNumber(value: length),
        siteDictionary.setObject(OFNumber(bool: legacy),
                                 forKey: SiteStorage.legacyField)
            SiteStorage.legacyField: NSNumber(value: isLegacy),
        if keyFile != nil {
            siteDictionary.setObject(keyFile!, forKey: SiteStorage.keyFileField)
        }

        siteDictionary.makeImmutable()
        ]
        siteDictionary[SiteStorage.keyFileField] = keyFile as AnyObject?
        storage.setObject(siteDictionary, forKey: name)

        storage[name] = siteDictionary
        self.update()
    }

    func removeSite(_ name: OFString) {
        self.storage.removeObject(forKey: name)
    func removeSite(_ name: String) {
        storage[name] = nil
        self.update()
    }

    private func update() {
        let ofStorage = (storage as NSDictionary).ofObject

        storage.messagePackRepresentation.write(toFile: path)
        sites = storage.allKeys.sorted
        ofStorage.messagePackRepresentation.write(toFile: path)
        sites = storage.keys.sorted()
    }
}