diff --git a/Kit/plugins/Server.swift b/Kit/plugins/Server.swift index 6e92eb58..7a473210 100644 --- a/Kit/plugins/Server.swift +++ b/Kit/plugins/Server.swift @@ -75,4 +75,24 @@ public class Server { } task.resume() } + + public func getTeamID(completionHandler: @escaping (_ result: String?, _ error: Error?) -> Void) { + guard let url = URL(string: "\(self.url)/team-id") else { + completionHandler(nil, "prepare url") + return + } + + var request = URLRequest(url: url) + request.httpMethod = "GET" + + let task = URLSession.shared.dataTask(with: request) { (data, _, err) in + guard let data = data, err == nil else { + completionHandler(nil, "no data or error \(String(describing: err))") + return + } + let str = String(decoding: data, as: UTF8.self) + completionHandler(str, nil) + } + task.resume() + } } diff --git a/Kit/plugins/Updater.swift b/Kit/plugins/Updater.swift index 1ff1c5c3..de9562ed 100644 --- a/Kit/plugins/Updater.swift +++ b/Kit/plugins/Updater.swift @@ -34,87 +34,91 @@ public struct Version { var beta: Int? = nil } -public class macAppUpdater { - private let user: String - private let repo: String +public class Updater { + private let github: URL + private let server: URL private let appName: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String private let currentVersion: String = "v\(Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String)" - public var latest: version_s? = nil + private var teamID: String? = nil private var observation: NSKeyValueObservation? - private var url: String { - return "https://api.github.com/repos/\(user)/\(repo)/releases/latest" - } - - public init(user: String, repo: String) { - self.user = user - self.repo = repo + public init(github: String, url: String) { + self.github = URL(string: "https://api.github.com/repos/\(github)/releases/latest")! + self.server = URL(string: url)! + + Server.shared.getTeamID { (val, err) in + if let teamID = val, err != nil { + self.teamID = teamID + } + } } deinit { - observation?.invalidate() + observation?.invalidate() } - public func check(completionHandler: @escaping (_ result: version_s?, _ error: Error?) -> Void) { + public func check(completion: @escaping (_ result: version_s?, _ error: Error?) -> Void) { if !isConnectedToNetwork() { - completionHandler(nil, "No internet connection") + completion(nil, "No internet connection") return } - fetchLastVersion { result, error in - guard error == nil else { - completionHandler(nil, error) + self.fetchRelease(uri: self.github) { (result, err) in + guard let result = result, err == nil else { + self.fetchRelease(uri: self.server) { (result, err) in + guard let result = result, err == nil else { + completion(nil, err) + return + } + + completion(version_s( + current: self.currentVersion, + latest: result.1, + newest: isNewestVersion(currentVersion: self.currentVersion, latestVersion: result.1), + url: result.0 + ), nil) + } return } - guard let results = result, results.count > 1 else { - completionHandler(nil, "wrong results") - return - } - - let downloadURL: String = result![1] - let lastVersion: String = result![0] - let newVersion: Bool = isNewestVersion(currentVersion: self.currentVersion, latestVersion: lastVersion) - - self.latest = version_s(current: self.currentVersion, latest: lastVersion, newest: newVersion, url: downloadURL) - completionHandler(self.latest, nil) + completion(version_s( + current: self.currentVersion, + latest: result.1, + newest: isNewestVersion(currentVersion: self.currentVersion, latestVersion: result.1), + url: result.0 + ), nil) } } - private func fetchLastVersion(completionHandler: @escaping (_ result: [String]?, _ error: Error?) -> Void) { - guard let url = URL(string: self.url) else { - completionHandler(nil, "wrong url") - return - } - - URLSession.shared.dataTask(with: url) { data, _, error in - guard let data = data, error == nil else { return } + private func fetchRelease(uri: URL, completion: @escaping (_ result: (String, String)?, _ error: Error?) -> Void) { + let task = URLSession.shared.dataTask(with: uri) { data, _, error in + guard let data = data, error == nil else { + completion(nil, "no data") + return + } do { let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) - guard let jsonArray = jsonResponse as? [String: Any] else { - completionHandler(nil, "parse json") + guard let jsonArray = jsonResponse as? [String: Any], + let lastVersion = jsonArray["tag_name"] as? String, + let assets = jsonArray["assets"] as? [[String: Any]], + let asset = assets.first(where: {$0["name"] as! String == "\(self.appName).dmg"}), + let downloadURL = asset["browser_download_url"] as? String else { + completion(nil, "parse json") return } - let lastVersion = jsonArray["tag_name"] as? String - guard let assets = jsonArray["assets"] as? [[String: Any]] else { - completionHandler(nil, "parse assets") - return - } - if let asset = assets.first(where: {$0["name"] as! String == "\(self.appName).dmg"}) { - let downloadURL = asset["browser_download_url"] as? String - completionHandler([lastVersion!, downloadURL!], nil) - } + completion((lastVersion, downloadURL), nil) } catch let parsingError { - completionHandler(nil, parsingError) + completion(nil, parsingError) } - }.resume() + } + task.resume() } - public func download(_ url: URL, progressHandler: @escaping (_ progress: Progress) -> Void = {_ in }, doneHandler: @escaping (_ path: String) -> Void = {_ in }) { + public func download(_ url: URL, progress: @escaping (_ progress: Progress) -> Void = {_ in }, completion: @escaping (_ path: String) -> Void = {_ in }) { let downloadTask = URLSession.shared.downloadTask(with: url) { urlOrNil, _, _ in guard let fileURL = urlOrNil else { return } do { @@ -127,15 +131,15 @@ public class macAppUpdater { return } - doneHandler(path) + completion(path) } } catch { print("file error: \(error)") } } - self.observation = downloadTask.progress.observe(\.fractionCompleted) { progress, _ in - progressHandler(progress) + self.observation = downloadTask.progress.observe(\.fractionCompleted) { value, _ in + progress(value) } downloadTask.resume() @@ -172,6 +176,21 @@ public class macAppUpdater { exit(0) } + public func isSignatureOK(path: String) -> Bool { + let line = syncShell("codesign -dv \(path) 2>&1 | grep TeamIdentifier") + let arr = line.split(separator: "=") + guard arr.count == 2 else { + return true + } + let teamID = arr[1] + + guard let externalTeamID = self.teamID else { + return true + } + + return externalTeamID == teamID + } + private func copyFile(from: URL, to: URL, completionHandler: @escaping (_ path: String, _ error: Error?) -> Void) { var toPath = to let fileName = (URL(fileURLWithPath: to.absoluteString)).lastPathComponent diff --git a/Stats/AppDelegate.swift b/Stats/AppDelegate.swift index 468b217c..336f74c6 100755 --- a/Stats/AppDelegate.swift +++ b/Stats/AppDelegate.swift @@ -21,7 +21,7 @@ import GPU import Fans import Bluetooth -let updater = macAppUpdater(user: "exelban", repo: "stats") +let updater = Updater(github: "exelban/stats", url: "https://api.serhiy.io/v1/stats/release/latest") var modules: [Module] = [ CPU(), GPU(), @@ -99,7 +99,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele if let uri = response.notification.request.content.userInfo["url"] as? String { debug("Downloading new version of app...") if let url = URL(string: uri) { - updater.download(url, doneHandler: { path in + updater.download(url, completion: { path in updater.install(path: path) }) } diff --git a/Stats/Views/Update.swift b/Stats/Views/Update.swift index c95c15f9..95cc4ad8 100644 --- a/Stats/Views/Update.swift +++ b/Stats/Views/Update.swift @@ -221,12 +221,12 @@ private class UpdateView: NSView { installButton.target = self installButton.isHidden = true - updater.download(url, progressHandler: { progress in + updater.download(url, progress: { progress in DispatchQueue.main.async { progressBar.doubleValue = progress.fractionCompleted state.stringValue = "\(Int(progress.fractionCompleted*100))%" } - }, doneHandler: { path in + }, completion: { path in self.path = path DispatchQueue.main.async { closeButton.setFrameSize(NSSize(width: view.frame.width/2, height: closeButton.frame.height)) @@ -253,6 +253,6 @@ private class UpdateView: NSView { } @objc private func install(_ sender: Any) { - updater.install(path: self.path) +// updater.install(path: self.path) } } diff --git a/Stats/helpers.swift b/Stats/helpers.swift index 5b16979b..ab84dafd 100644 --- a/Stats/helpers.swift +++ b/Stats/helpers.swift @@ -145,7 +145,7 @@ extension AppDelegate { if silent { if let url = URL(string: version.url) { - updater.download(url, doneHandler: { path in + updater.download(url, completion: { path in updater.install(path: path) }) }