secretive/Brief/Updater.swift

112 lines
2.7 KiB
Swift
Raw Normal View History

2020-03-15 08:01:40 +00:00
import Foundation
import Combine
2020-03-22 01:43:26 +00:00
public protocol UpdaterProtocol: ObservableObject {
2020-03-15 08:01:40 +00:00
var update: Release? { get }
}
2020-03-22 01:43:26 +00:00
public class Updater: ObservableObject, UpdaterProtocol {
2020-03-15 08:01:40 +00:00
2020-03-22 01:43:26 +00:00
@Published public var update: Release?
2020-03-15 08:01:40 +00:00
2020-03-22 01:43:26 +00:00
public init() {
2020-03-15 08:01:40 +00:00
checkForUpdates()
let timer = Timer.scheduledTimer(withTimeInterval: 60*60*24, repeats: true) { _ in
self.checkForUpdates()
}
timer.tolerance = 60*60
}
2020-03-22 01:43:26 +00:00
public func checkForUpdates() {
2020-03-15 08:01:40 +00:00
URLSession.shared.dataTask(with: Constants.updateURL) { data, _, _ in
guard let data = data else { return }
guard let release = try? JSONDecoder().decode(Release.self, from: data) else { return }
self.evaluate(release: release)
}.resume()
}
public func ignore(release: Release) {
guard !release.critical else { return }
defaults.set(true, forKey: release.name)
DispatchQueue.main.async {
self.update = nil
}
}
}
extension Updater {
2020-03-15 08:01:40 +00:00
func evaluate(release: Release) {
guard !userIgnored(release: release) else { return }
2020-03-15 08:01:40 +00:00
let latestVersion = semVer(from: release.name)
let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)
for (latest, current) in zip(latestVersion, currentVersion) {
if latest > current {
DispatchQueue.main.async {
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 {
guard !release.critical else { return false }
return defaults.bool(forKey: release.name)
}
var defaults: UserDefaults {
UserDefaults(suiteName: "com.maxgoedjen.Secretive.updater.ignorelist")!
}
2020-03-15 08:01:40 +00:00
}
extension Updater {
enum Constants {
static let updateURL = URL(string: "https://api.github.com/repos/maxgoedjen/secretive/releases/latest")!
}
}
2020-03-22 01:43:26 +00:00
public struct Release: Codable {
public let name: String
public let html_url: URL
public let body: String
2020-03-22 02:28:49 +00:00
public init(name: String, html_url: URL, body: String) {
2020-03-22 01:43:26 +00:00
self.name = name
self.html_url = html_url
self.body = body
}
2020-03-15 08:01:40 +00:00
}
extension Release {
2020-03-22 01:43:26 +00:00
public var critical: Bool {
2020-03-15 08:01:40 +00:00
return body.contains(Constants.securityContent)
}
}
extension Release {
enum Constants {
static let securityContent = "Critical Security Update"
}
}