From 8288dea897ed5a70140ffc2880477d57542419d5 Mon Sep 17 00:00:00 2001 From: Janez Troha Date: Thu, 16 Sep 2021 12:06:38 +0200 Subject: [PATCH] More frequent update checks --- Pareto/AppInfo.swift | 38 +++++----- Pareto/Flags.swift | 26 ++++++- Pareto/Info.plist | 2 +- Pareto/ParetoApp.swift | 83 +++++++++++++--------- Pareto/Settings.swift | 1 - Pareto/StatusBar/StatusBarController.swift | 2 +- Pareto/Views/AboutSettingsView.swift | 11 ++- 7 files changed, 106 insertions(+), 57 deletions(-) diff --git a/Pareto/AppInfo.swift b/Pareto/AppInfo.swift index 9d1ed06..f01c14a 100644 --- a/Pareto/AppInfo.swift +++ b/Pareto/AppInfo.swift @@ -68,24 +68,26 @@ enum AppInfo { logs.append("\(k)=\(v)") } } - logs.append("\nLogs:") - do { - if #available(macOS 12.0, *) { - let logStore = try OSLogStore(scope: .currentProcessIdentifier) - let enumerator = try logStore.__entriesEnumerator(position: nil, predicate: nil) - let allEntries = Array(enumerator) - let osLogEntryObjects = allEntries.compactMap { $0 as? OSLogEntry } - let osLogEntryLogObjects = osLogEntryObjects.compactMap { $0 as? OSLogEntryLog } - let subsystem = Bundle.main.bundleIdentifier! - for entry in osLogEntryLogObjects where entry.subsystem == subsystem { - logs.append(entry.category + ": " + entry.composedMessage) - } - } else { - logs.append("Please copy the logs from the Konsole.app with the ParetoSecurity filter.") - } - } catch { - logs.append("logEntries: \(error)") - } + // Disabled due to apple pulling SDK 12 + // https://www.reddit.com/r/SwiftUI/comments/pocuh6/xcode_13_rc_they_have_temporarly_removed_macos_12/?utm_source=amp&utm_medium= + // logs.append("\nLogs:") + // do { + // if #available(macOS 12.0, *) { + // let logStore = try OSLogStore(scope: .currentProcessIdentifier) + // let enumerator = try logStore.__entriesEnumerator(position: nil, predicate: nil) + // let allEntries = Array(enumerator) + // let osLogEntryObjects = allEntries.compactMap { $0 as? OSLogEntry } + // let osLogEntryLogObjects = osLogEntryObjects.compactMap { $0 as? OSLogEntryLog } + // let subsystem = Bundle.main.bundleIdentifier! + // for entry in osLogEntryLogObjects where entry.subsystem == subsystem { + // logs.append(entry.category + ": " + entry.composedMessage) + // } + // } else { + // logs.append("Please copy the logs from the Konsole.app with the ParetoSecurity filter.") + // } + // } catch { + // logs.append("logEntries: \(error)") + // } return logs } diff --git a/Pareto/Flags.swift b/Pareto/Flags.swift index f22036a..3feb005 100644 --- a/Pareto/Flags.swift +++ b/Pareto/Flags.swift @@ -7,15 +7,37 @@ import Foundation +struct DNSResponse: Codable { + let status: Int + + struct Answer: Codable { + let name: String + let type, ttl: Int + let data: String + enum CodingKeys: String, CodingKey { + case name, type + case ttl = "TTL" + case data + } + } + + let answer: [Answer] + + enum CodingKeys: String, CodingKey { + case status = "Status" + case answer = "Answer" + } +} + struct Flags: Decodable { var personalLicense: Bool = false } -func getLatestFlags() throws -> Flags? { +func getLatestFlags() throws -> String? { guard Bundle.main.executableURL != nil else { throw Error.bundleExecutableURL } let url = URL(string: "https://dns.google/resolve?name=flags.paretosecurity.app&type=txt")! let data = try Data(contentsOf: url) - return try JSONDecoder().decode(Flags.self, from: data) + return try JSONDecoder().decode(DNSResponse.self, from: data).answer.first?.data } diff --git a/Pareto/Info.plist b/Pareto/Info.plist index f42da3e..098df88 100644 --- a/Pareto/Info.plist +++ b/Pareto/Info.plist @@ -26,7 +26,7 @@ CFBundleVersion - 1854 + 1875 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion diff --git a/Pareto/ParetoApp.swift b/Pareto/ParetoApp.swift index c78a86c..d87cd84 100644 --- a/Pareto/ParetoApp.swift +++ b/Pareto/ParetoApp.swift @@ -15,14 +15,6 @@ class AppDelegate: NSObject, NSApplicationDelegate { var statusBar: StatusBarController? var updater: AppUpdater? - func application(_: NSApplication, open urls: [URL]) { - for url in urls { - if url.host == "enroll" { - Defaults[.license] = url.queryParams()["token"] ?? "" - } - } - } - #if !DEBUG func applicationWillFinishLaunching(_: Notification) { if !Bundle.main.path.string.hasPrefix("/Applications/") { @@ -36,11 +28,22 @@ class AppDelegate: NSObject, NSApplicationDelegate { } #endif + func application(_: NSApplication, open urls: [URL]) { + for url in urls { + switch url.host { + case "reset": + resetSettings() + default: + os_log("Unknown command \(url)") + } + } + } + func applicationDidFinishLaunching(_: Notification) { statusBar = StatusBarController() statusBar?.configureChecks() statusBar?.updateMenu() - Defaults[.updateRunning] = 0 + updater = AppUpdater(owner: "ParetoSecurity", repo: "pareto-mac") // stop running checks here and reset to defaults @@ -53,9 +56,24 @@ class AppDelegate: NSObject, NSApplicationDelegate { } statusBar?.runChecks() + // schedule update on startup + if Defaults.shouldDoUpdateCheck() { + os_log("Running update check from startup") + DispatchQueue.main.async { + self.checkForRelease() + Defaults.doneUpdateCheck() + } + } // Update when waking up from sleep NSWorkspace.onWakeup { _ in self.statusBar?.runChecks() + if Defaults.shouldDoUpdateCheck() { + os_log("Running update check from wakeup") + DispatchQueue.main.async { + self.checkForRelease() + Defaults.doneUpdateCheck() + } + } } // Schedule hourly claim updates @@ -66,45 +84,36 @@ class AppDelegate: NSObject, NSApplicationDelegate { } NSBackgroundActivityScheduler.repeating(withName: "UpdateRunner", withInterval: 60 * 60) { (completion: NSBackgroundActivityScheduler.CompletionHandler) in - os_log("Running update checks") - os_log("Doing checkForRelease \(Defaults[.updateRunning])") - if Defaults[.updateRunning] > 0 { - os_log("Skip checkForRelease Defaults[.updateRunning]=\(Defaults[.updateRunning])") - return - } if Defaults.shouldDoUpdateCheck() { os_log("Running update check") - DispatchQueue.main.async { self.checkForRelease() } - Defaults.doneUpdateCheck() + DispatchQueue.main.async { + self.checkForRelease() + Defaults.doneUpdateCheck() + } } completion(.finished) } } func checkForRelease() { - Defaults[.updateRunning] += 1 let currentVersion = Bundle.main.version if let release = try? updater!.getLatestRelease() { if currentVersion < release.version { if let zipURL = release.assets.filter({ $0.browser_download_url.path.hasSuffix(".zip") }).first { - let alert = NSAlert() - alert.messageText = "New version of Pareto Security \(release.version) is available" - alert.informativeText = release.body - alert.alertStyle = NSAlert.Style.informational - alert.addButton(withTitle: "Download") - alert.addButton(withTitle: "Skip") - if alert.runModal() == NSApplication.ModalResponse.alertFirstButtonReturn { - DispatchQueue.main.async { - let done = self.updater!.downloadAndUpdate(withAsset: zipURL) - if !done { - if let dmgURL = release.assets.filter({ $0.browser_download_url.path.hasSuffix(".dmg") }).first { - NSWorkspace.shared.open(dmgURL.browser_download_url) - } + let done = updater!.downloadAndUpdate(withAsset: zipURL) + // Failed to update + if !done { + if let dmgURL = release.assets.filter({ $0.browser_download_url.path.hasSuffix(".dmg") }).first { + let alert = NSAlert() + alert.messageText = "New version of Pareto Security \(release.version) is available" + alert.informativeText = release.body + alert.alertStyle = NSAlert.Style.informational + alert.addButton(withTitle: "Download") + if alert.runModal() == NSApplication.ModalResponse.alertFirstButtonReturn { + NSWorkspace.shared.open(dmgURL.browser_download_url) } } } - Defaults[.updateRunning] = 0 - os_log("Defaults[.updateRunning] \(Defaults[.updateRunning])") } } } @@ -126,6 +135,14 @@ class AppDelegate: NSObject, NSApplicationDelegate { @objc func reportBug() { NSWorkspace.shared.open(AppInfo.bugReportURL()) } + + func resetSettings() { + Defaults.removeAll() + UserDefaults.standard.removeAll() + UserDefaults.standard.synchronize() + Defaults[.firstLaunch] = true + NSApplication.shared.terminate(self) + } } @main diff --git a/Pareto/Settings.swift b/Pareto/Settings.swift index dc827d3..b45019c 100644 --- a/Pareto/Settings.swift +++ b/Pareto/Settings.swift @@ -17,7 +17,6 @@ extension Defaults.Keys { static let firstLaunch = Key("firstLaunch", default: true) static let betaChannel = Key("betaChannel", default: false) - static let updateRunning = Key("updateRunning", default: 0) static let internalRunChecks = Key("internalRunChecks", default: false) static let snoozeTime = Key("snoozeTime", default: 0) static let lastCheck = Key("lastCheck", default: 0) diff --git a/Pareto/StatusBar/StatusBarController.swift b/Pareto/StatusBar/StatusBarController.swift index 9e2c5b6..499ca0d 100644 --- a/Pareto/StatusBar/StatusBarController.swift +++ b/Pareto/StatusBar/StatusBarController.swift @@ -47,7 +47,7 @@ class StatusBarController: NSObject, NSMenuDelegate { statusItem.menu = statusItemMenu if Defaults[.firstLaunch] { if let button = statusItem.button { - _ = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in + _ = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in button.performClick(nil) } } diff --git a/Pareto/Views/AboutSettingsView.swift b/Pareto/Views/AboutSettingsView.swift index 6a432d5..bb46edf 100644 --- a/Pareto/Views/AboutSettingsView.swift +++ b/Pareto/Views/AboutSettingsView.swift @@ -52,7 +52,16 @@ struct AboutSettingsView: View { VStack(alignment: .leading, spacing: 0) { Text("Version: \(AppInfo.appVersion) - \(AppInfo.buildVersion)") HStack { - Text(status.rawValue) + if status == UpdateStates.Failed { + HStack(spacing: 0) { + Text("Failed to update, ") + Link("download manualy", + destination: URL(string: "https://github.com/ParetoSecurity/pareto-mac/releases/latest/download/ParetoSecurity.dmg")!) + } + } else { + Text(status.rawValue) + } + if self.isLoading { ProgressView().frame(width: 5.0, height: 5.0) .scaleEffect(x: 0.5, y: 0.5, anchor: .center)