Compare commits

..

4 Commits

Author SHA1 Message Date
cd0a1b0a68 Fixignoring bugs 2020-11-12 23:48:56 -08:00
8bbf489146 Relaunch agent if updated (#86) 2020-04-04 15:16:31 -07:00
30148ee3a4 Revert "Xcode 11.4 changes"
This reverts commit c306801149.
2020-04-03 00:44:13 -07:00
c306801149 Xcode 11.4 changes 2020-04-02 18:22:59 -07:00
10 changed files with 146 additions and 25 deletions

View File

@ -4,6 +4,7 @@ import Combine
public protocol UpdaterProtocol: ObservableObject { public protocol UpdaterProtocol: ObservableObject {
var update: Release? { get } var update: Release? { get }
func ignore(release: Release)
} }
@ -41,25 +42,14 @@ extension Updater {
func evaluate(release: Release) { func evaluate(release: Release) {
guard !userIgnored(release: release) else { return } guard !userIgnored(release: release) else { return }
let latestVersion = semVer(from: release.name) let latestVersion = SemVer(release.name)
let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String) let currentVersion = SemVer(Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)
for (latest, current) in zip(latestVersion, currentVersion) { if latestVersion > currentVersion {
if latest > current {
DispatchQueue.main.async { DispatchQueue.main.async {
self.update = release self.update = release
} }
return
} }
} }
}
func semVer(from stringVersion: String) -> [Int] {
var split = stringVersion.split(separator: ".").compactMap { Int($0) }
while split.count < 3 {
split.append(0)
}
return split
}
func userIgnored(release: Release) -> Bool { func userIgnored(release: Release) -> Bool {
guard !release.critical else { return false } guard !release.critical else { return false }
@ -71,6 +61,38 @@ extension Updater {
} }
} }
struct SemVer {
let versionNumbers: [Int]
init(_ version: String) {
// Betas have the format 1.2.3_beta1
let strippedBeta = version.split(separator: "_").first!
var split = strippedBeta.split(separator: ".").compactMap { Int($0) }
while split.count < 3 {
split.append(0)
}
versionNumbers = split
}
}
extension SemVer: Comparable {
static func < (lhs: SemVer, rhs: SemVer) -> Bool {
for (latest, current) in zip(lhs.versionNumbers, rhs.versionNumbers) {
if latest < current {
return true
} else if latest > current {
return false
}
}
return false
}
}
extension Updater { extension Updater {
enum Constants { enum Constants {
@ -93,11 +115,18 @@ public struct Release: Codable {
} }
extension Release: Identifiable {
public var id: String {
html_url.absoluteString
}
}
extension Release { extension Release {
public var critical: Bool { public var critical: Bool {
return body.contains(Constants.securityContent) body.contains(Constants.securityContent)
} }
} }

View File

@ -13,7 +13,7 @@ class Notifier {
let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: "Update", options: []) let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: "Update", options: [])
let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: "Ignore", options: []) let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: "Ignore", options: [])
let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: []) let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: [])
let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: []) let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.criticalUpdateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory]) UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory])
UNUserNotificationCenter.current().delegate = notificationDelegate UNUserNotificationCenter.current().delegate = notificationDelegate
} }

View File

@ -10,6 +10,8 @@
50020BB024064869003D4025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50020BAF24064869003D4025 /* AppDelegate.swift */; }; 50020BB024064869003D4025 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50020BAF24064869003D4025 /* AppDelegate.swift */; };
5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; }; 5018F54F24064786002EB505 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5018F54E24064786002EB505 /* Notifier.swift */; };
50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; }; 50524B442420969E008DBD97 /* OpenSSHWriterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */; };
50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */; };
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50571E0424393D1500F76F6C /* LaunchAgentController.swift */; };
50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* AppDelegate.swift */; }; 50617D8323FCE48E0099B055 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8223FCE48E0099B055 /* AppDelegate.swift */; };
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; }; 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50617D8423FCE48E0099B055 /* ContentView.swift */; };
50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; }; 50617D8723FCE48E0099B055 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50617D8623FCE48E0099B055 /* Assets.xcassets */; };
@ -206,6 +208,8 @@
50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 50020BAF24064869003D4025 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; }; 5018F54E24064786002EB505 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = "<group>"; };
50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSHWriterTests.swift; sourceTree = "<group>"; }; 50524B432420969D008DBD97 /* OpenSSHWriterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSSHWriterTests.swift; sourceTree = "<group>"; };
50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustUpdatedChecker.swift; sourceTree = "<group>"; };
50571E0424393D1500F76F6C /* LaunchAgentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchAgentController.swift; sourceTree = "<group>"; };
50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50617D7F23FCE48E0099B055 /* Secretive.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretive.app; sourceTree = BUILT_PRODUCTS_DIR; };
50617D8223FCE48E0099B055 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 50617D8223FCE48E0099B055 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 50617D8423FCE48E0099B055 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
@ -512,6 +516,8 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */, 508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */,
50571E0424393D1500F76F6C /* LaunchAgentController.swift */,
); );
path = Controllers; path = Controllers;
sourceTree = "<group>"; sourceTree = "<group>";
@ -916,10 +922,12 @@
files = ( files = (
50C385A9240B636500AF2719 /* SetupView.swift in Sources */, 50C385A9240B636500AF2719 /* SetupView.swift in Sources */,
50617D8523FCE48E0099B055 /* ContentView.swift in Sources */, 50617D8523FCE48E0099B055 /* ContentView.swift in Sources */,
50571E0324393C2600F76F6C /* JustUpdatedChecker.swift in Sources */,
50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */, 50617DD223FCEFA90099B055 /* PreviewStore.swift in Sources */,
508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */, 508A58B3241ED2180069DC07 /* AgentStatusChecker.swift in Sources */,
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */, 50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */, 5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
50571E0524393D1500F76F6C /* LaunchAgentController.swift in Sources */,
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */, 50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,
50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */, 50BB046B2418AAAE00D6E079 /* EmptyStoreView.swift in Sources */,
50731669241E00C20023809E /* NoticeView.swift in Sources */, 50731669241E00C20023809E /* NoticeView.swift in Sources */,

View File

@ -17,6 +17,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}() }()
let updater = Updater() let updater = Updater()
let agentStatusChecker = AgentStatusChecker() let agentStatusChecker = AgentStatusChecker()
let justUpdatedChecker = JustUpdatedChecker()
func applicationDidFinishLaunching(_ aNotification: Notification) { func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = ContentView(storeList: storeList, updater: updater, agentStatusChecker: agentStatusChecker, runSetupBlock: { self.runSetup(sender: nil) }) let contentView = ContentView(storeList: storeList, updater: updater, agentStatusChecker: agentStatusChecker, runSetupBlock: { self.runSetup(sender: nil) })
@ -40,6 +41,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
newMenuItem.isEnabled = true newMenuItem.isEnabled = true
} }
runSetupIfNeeded() runSetupIfNeeded()
relaunchAgentIfNeeded()
} }
func applicationDidBecomeActive(_ notification: Notification) { func applicationDidBecomeActive(_ notification: Notification) {
@ -89,6 +91,12 @@ extension AppDelegate {
} }
} }
func relaunchAgentIfNeeded() {
if agentStatusChecker.running && justUpdatedChecker.justUpdated {
LaunchAgentController().relaunch()
}
}
} }
extension AppDelegate { extension AppDelegate {

View File

@ -0,0 +1,36 @@
import Foundation
import Combine
import AppKit
protocol JustUpdatedCheckerProtocol: ObservableObject {
var justUpdated: Bool { get }
}
class JustUpdatedChecker: ObservableObject, JustUpdatedCheckerProtocol {
@Published var justUpdated: Bool = false
init() {
check()
}
func check() {
let lastBuild = UserDefaults.standard.object(forKey: Constants.previousVersionUserDefaultsKey) as? String ?? "None"
let currentBuild = Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String
UserDefaults.standard.set(currentBuild, forKey: Constants.previousVersionUserDefaultsKey)
if lastBuild != currentBuild {
justUpdated = true
}
}
}
extension JustUpdatedChecker {
enum Constants {
static let previousVersionUserDefaultsKey = "com.maxgoedjen.Secretive.lastBuild"
}
}

View File

@ -0,0 +1,19 @@
import Foundation
import ServiceManagement
struct LaunchAgentController {
func install() -> Bool {
setEnabled(true)
}
func relaunch() {
_ = setEnabled(false)
_ = setEnabled(true)
}
private func setEnabled(_ enabled: Bool) -> Bool {
SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, enabled)
}
}

View File

@ -17,6 +17,8 @@ class PreviewUpdater: UpdaterProtocol {
} }
} }
func ignore(release: Release) {
}
} }
extension PreviewUpdater { extension PreviewUpdater {

View File

@ -87,9 +87,13 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
severity = .advisory severity = .advisory
text = "Update Available" text = "Update Available"
} }
return AnyView(NoticeView(text: text, severity: severity, actionTitle: "Update") { let action = {
NSWorkspace.shared.open(update.html_url) _ = NSWorkspace.shared.open(update.html_url)
}) }
let ignoreAction = {
updater.ignore(release: update)
}
return AnyView(NoticeView(text: text, severity: severity, actionTitle: "Update", action: action, secondaryActionTitle: "Ignore", secondaryAction: ignoreAction))
} }
func agentNotice() -> some View { func agentNotice() -> some View {

View File

@ -7,12 +7,28 @@ struct NoticeView: View {
let severity: Severity let severity: Severity
let actionTitle: String? let actionTitle: String?
let action: (() -> Void)? let action: (() -> Void)?
let secondaryActionTitle: String?
let secondaryAction: (() -> Void)?
public init(text: String, severity: NoticeView.Severity, actionTitle: String?, action: (() -> Void)?, secondaryActionTitle: String? = nil, secondaryAction: (() -> Void)? = nil) {
self.text = text
self.severity = severity
self.actionTitle = actionTitle
self.action = action
self.secondaryActionTitle = secondaryActionTitle
self.secondaryAction = secondaryAction
}
var body: some View { var body: some View {
HStack { HStack {
Text(text).bold() Text(text).bold()
Spacer() Spacer()
if action != nil { if action != nil {
if secondaryAction != nil {
Button(action: secondaryAction!) {
Text(secondaryActionTitle!)
}
}
Button(action: action!) { Button(action: action!) {
Text(actionTitle!) Text(actionTitle!)
} }

View File

@ -1,6 +1,5 @@
import Foundation import Foundation
import SwiftUI import SwiftUI
import ServiceManagement
struct SetupView: View { struct SetupView: View {
@ -117,7 +116,7 @@ struct SetupStepCommandView: View {
extension SetupView { extension SetupView {
func installLaunchAgent() -> Bool { func installLaunchAgent() -> Bool {
SMLoginItemSetEnabled("com.maxgoedjen.Secretive.SecretAgent" as CFString, true) LaunchAgentController().install()
} }
func markAsDone() -> Bool { func markAsDone() -> Bool {