-
Notifications
You must be signed in to change notification settings - Fork 85
/
Shared.swift
250 lines (219 loc) · 7.5 KB
/
Shared.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//
// SharedConstants.swift
// LockdowniOS
//
// Created by Johnny Lin on 8/8/19.
// Copyright © 2019 Confirmed Inc. All rights reserved.
//
// These are constants and functions shared by the main app and the extensions
import Foundation
import CocoaLumberjackSwift
import KeychainAccess
import Reachability
let isTestFlight = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt"
var appInstallDate: Date? {
if let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
if let installDate = try! FileManager.default.attributesOfItem(atPath: documentsFolder.path)[.creationDate] as? Date {
return installDate
}
}
return nil
}
func appHasJustBeenUpgradedOrIsNewInstall() -> Bool {
let currentVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
let versionOfLastRun = UserDefaults.standard.object(forKey: "VersionOfLastRun") as? String
DDLogInfo("APP UPGRADED CHECK: LAST RUN \(versionOfLastRun ?? "n/a") | CURRENT \(currentVersion ?? "n/a")")
UserDefaults.standard.set(currentVersion, forKey: "VersionOfLastRun")
if (versionOfLastRun == nil || versionOfLastRun != currentVersion) {
// either first time this check has occurred, or app was updated since last run
DDLogInfo("APP UPGRADED CHECK: TRUE - LAST RUN \(versionOfLastRun ?? "n/a") | CURRENT \(currentVersion ?? "n/a")")
return true
} else {
// nothing changed
DDLogInfo("APP UPGRADED CHECK: FALSE")
return false
}
}
let reachability = Reachability()
let keychain = Keychain(service: "com.confirmed.tunnels").synchronizable(true)
// MARK: - VPN Credentials
let kVPNCredentialsKeyBase64 = "VPNCredentialsKeyBase64"
let kVPNCredentialsId = "VPNCredentialsId"
let kICloudContainer = "iCloud.com.confirmed.lockdown"
let kOpenFirewallTunnelRecord = "OpenFirewallTunnelRemotely"
let kCloseFirewallTunnelRecord = "CloseFirewallTunnelRemotely"
let kRestartFirewallTunnelRecord = "RestartFirewallTunnelRemotely"
struct VPNCredentials {
var id: String = ""
var keyBase64: String = ""
}
func setVPNCredentials(id: String, keyBase64: String) throws {
DDLogInfo("Setting VPN Credentials: \(id), base64: \(keyBase64)")
if (id == "") {
throw "ID was blank"
}
if (keyBase64 == "") {
throw "Key was blank"
}
do {
try keychain.set(id, key: kVPNCredentialsId)
try keychain.set(keyBase64, key: kVPNCredentialsKeyBase64)
}
catch {
throw "Unable to set VPN credentials on keychain"
}
}
func getVPNCredentials() -> VPNCredentials? {
DDLogInfo("Getting stored VPN credentials")
var id: String? = nil
do {
id = try keychain.get(kVPNCredentialsId)
if id == nil {
DDLogError("No stored credential id")
return nil
}
}
catch {
DDLogError("Error getting stored VPN credentials id: \(error)")
return nil
}
var keyBase64: String? = nil
do {
keyBase64 = try keychain.get(kVPNCredentialsKeyBase64)
if keyBase64 == nil {
DDLogError("No stored credential keyBase64")
return nil
}
}
catch {
DDLogError("Error getting stored VPN credentials keyBase64: \(error)")
return nil
}
DDLogInfo("Returning stored VPN credentials: \(id!) \(keyBase64!)")
return VPNCredentials(id: id!, keyBase64: keyBase64!)
}
// MARK: - API Credentials
let kAPICredentialsEmail = "APICredentialsEmail"
let kAPICredentialsPassword = "APICredentialsPassword"
struct APICredentials {
var email: String = ""
var password: String = ""
}
func setAPICredentials(email: String, password: String) throws {
DDLogInfo("Setting API Credentials with email: \(email)")
if (email == "") {
throw "Email was blank"
}
if (password == "") {
throw "Password was blank"
}
do {
try keychain.set(email, key: kAPICredentialsEmail)
try keychain.set(password, key: kAPICredentialsPassword)
}
catch {
throw "Unable to set API credentials on keychain"
}
}
func clearAPICredentials() {
try? keychain.remove(kAPICredentialsEmail)
try? keychain.remove(kAPICredentialsPassword)
}
func getAPICredentials() -> APICredentials? {
print("Getting stored API credentials")
var email: String? = nil
do {
email = try keychain.get(kAPICredentialsEmail)
if email == nil {
print("No stored API credential email")
return nil
}
}
catch {
print("Error getting stored API credentials email: \(error)")
return nil
}
var password: String? = nil
do {
password = try keychain.get(kAPICredentialsPassword)
if password == nil {
print("No stored API credential password")
return nil
}
}
catch {
print("Error getting stored API credentials password: \(error)")
return nil
}
print("Returning stored API credentials with email: \(email!)")
return APICredentials(email: email!, password: password!)
}
let kAPICredentialsConfirmed = "APICredentialsConfirmed"
func getAPICredentialsConfirmed() -> Bool {
return defaults.bool(forKey: kAPICredentialsConfirmed)
}
func setAPICredentialsConfirmed(confirmed: Bool) {
defaults.set(confirmed, forKey: kAPICredentialsConfirmed)
}
// MARK: - Extensions
extension String: Error { // Error makes it easy to throw errors as one-liners
func base64Encoded() -> String? {
if let data = self.data(using: .utf8) {
return data.base64EncodedString()
}
return nil
}
func base64Decoded() -> String? {
if let data = Data(base64Encoded: self) {
return String(data: data, encoding: .utf8)
}
return nil
}
}
extension UIColor {
static let confirmedBlue = UIColor(named: "Confirmed Blue") ?? UIColor.tunnelsBlue
static let tunnelsBlue = UIColor(red: 0/255.0, green: 173/255.0, blue: 231/255.0, alpha: 1.0)
static let tunnelsWarning = UIColor(red: 231/255.0, green: 76/255.0, blue: 68/255.0, alpha: 1.0)
static let tunnelsDarkBlue = UIColor(red: 0/255.0, green: 117/255.0, blue: 157/255.0, alpha: 1.0)
}
extension UnicodeScalar {
var hexNibble:UInt8 {
let value = self.value
if 48 <= value && value <= 57 {
return UInt8(value - 48)
}
else if 65 <= value && value <= 70 {
return UInt8(value - 55)
}
else if 97 <= value && value <= 102 {
return UInt8(value - 87)
}
fatalError("\(self) not a legal hex nibble")
}
}
extension Data {
init(hex: String) {
let scalars = hex.unicodeScalars
var bytes = Array<UInt8>(repeating: 0, count: (scalars.count + 1) >> 1)
for (index, scalar) in scalars.enumerated() {
var nibble = scalar.hexNibble
if index & 1 == 0 {
nibble <<= 4
}
bytes[index >> 1] |= nibble
}
self = Data(bytes: bytes)
}
}
extension UIDevice {
var modelName: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
return identifier
}
}