From d2b178e68ffbb35f17ee35155842da97ddcfd7f4 Mon Sep 17 00:00:00 2001 From: Alan Hamlett Date: Wed, 27 Mar 2024 20:37:55 -0400 Subject: [PATCH] Warn when conflicting browser extension detected --- WakaTime/Helpers/Dependencies.swift | 56 +++++++++++++++++++++++++++++ WakaTime/WakaTime.swift | 10 ++++++ 2 files changed, 66 insertions(+) diff --git a/WakaTime/Helpers/Dependencies.swift b/WakaTime/Helpers/Dependencies.swift index 6510a62..51e3f71 100644 --- a/WakaTime/Helpers/Dependencies.swift +++ b/WakaTime/Helpers/Dependencies.swift @@ -15,6 +15,62 @@ class Dependencies { Bundle.main.version == "local-build" } + public static func recentBrowserExtension() async -> String? { + guard + let apiKey = ConfigFile.getSetting(section: "settings", key: "api_key"), + !apiKey.isEmpty + else { return nil } + let url = "https://api.wakatime.com/api/v1/users/current/user_agents?api_key=\(apiKey)" + let request = URLRequest(url: URL(string: url)!, cachePolicy: .reloadIgnoringCacheData) + do { + let (data, response) = try await URLSession.shared.data(for: request) + guard + let httpResponse = response as? HTTPURLResponse, + httpResponse.statusCode == 200 + else { return nil } + + struct Resp: Decodable { + let data: [UserAgent] + } + struct UserAgent: Decodable { + let isBrowserExtension: Bool + let editor: String? + let lastSeenAt: String? + enum CodingKeys: String, CodingKey { + case isBrowserExtension = "is_browser_extension" + case editor + case lastSeenAt = "last_seen_at" + } + } + + let release = try JSONDecoder().decode(Resp.self, from: data) + let now = Date() + for agent in release.data { + guard + agent.isBrowserExtension, + let editor = agent.editor, + !editor.isEmpty, + let lastSeenAt = agent.lastSeenAt + else { continue } + + let isoDateFormatter = ISO8601DateFormatter() + isoDateFormatter.timeZone = TimeZone(secondsFromGMT: 0) + isoDateFormatter.formatOptions = [.withInternetDateTime] + if let lastSeen = isoDateFormatter.date(from: lastSeenAt) { + if now.timeIntervalSince(lastSeen) > 600 { + break + } + } + + return agent.editor + } + } catch { + Logging.default.log("Request error checking for conflicting browser extension: \(error)") + return nil + } + return nil + } + private static func getLatestVersion() async throws -> String? { struct Release: Decodable { let tagName: String diff --git a/WakaTime/WakaTime.swift b/WakaTime/WakaTime.swift index dced6c2..1dc0c78 100644 --- a/WakaTime/WakaTime.swift +++ b/WakaTime/WakaTime.swift @@ -50,6 +50,16 @@ class WakaTime: HeartbeatEventHandler { } PropertiesManager.hasLaunchedBefore = true } + + if MonitoringManager.isMonitoringBrowsing { + Task { + if let browser = await Dependencies.recentBrowserExtension() { + delegate.toastNotification("Warning: WakaTime \(browser) extension detected. " + + "It’s recommended to only track browsing activity with the \(browser) " + + "extension or Mac Desktop app, but not both.") + } + } + } } private func configureFirebase() {