mirror of
https://github.com/seemoo-lab/openhaystack.git
synced 2026-04-19 16:26:41 +00:00
Create a SetttingsView to manually enter Search Party Token, add error handling for expired token
This commit is contained in:
committed by
Alexander Heinrich
parent
3ef4280df1
commit
17410e2c00
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 52;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@@ -58,6 +58,7 @@
|
||||
78EC227225DBC8CE0042B775 /* Accessory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC227125DBC8CE0042B775 /* Accessory.swift */; };
|
||||
78EC227725DBDB7E0042B775 /* KeychainController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78EC227625DBDB7E0042B775 /* KeychainController.swift */; };
|
||||
78F8BB4C261C50EB00D9F37F /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78F8BB4B261C50EB00D9F37F /* LargeButtonStyle.swift */; };
|
||||
9ED440A02C1605EF002574D1 /* OpenHaystackSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ED4409F2C1605EF002574D1 /* OpenHaystackSettingsView.swift */; };
|
||||
F126102F2600D1D80066A859 /* Slider+LogScale.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126102E2600D1D80066A859 /* Slider+LogScale.swift */; };
|
||||
F12D5A5A25FA4F3500CBBA09 /* BluetoothAccessoryScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12D5A5925FA4F3500CBBA09 /* BluetoothAccessoryScanner.swift */; };
|
||||
F12D5A6025FA79FA00CBBA09 /* Advertisement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12D5A5F25FA79FA00CBBA09 /* Advertisement.swift */; };
|
||||
@@ -169,6 +170,7 @@
|
||||
78EC227125DBC8CE0042B775 /* Accessory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessory.swift; sourceTree = "<group>"; };
|
||||
78EC227625DBDB7E0042B775 /* KeychainController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainController.swift; sourceTree = "<group>"; };
|
||||
78F8BB4B261C50EB00D9F37F /* LargeButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeButtonStyle.swift; sourceTree = "<group>"; };
|
||||
9ED4409F2C1605EF002574D1 /* OpenHaystackSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHaystackSettingsView.swift; sourceTree = "<group>"; };
|
||||
F126102E2600D1D80066A859 /* Slider+LogScale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Slider+LogScale.swift"; sourceTree = "<group>"; };
|
||||
F12D5A5925FA4F3500CBBA09 /* BluetoothAccessoryScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothAccessoryScanner.swift; sourceTree = "<group>"; };
|
||||
F12D5A5F25FA79FA00CBBA09 /* Advertisement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advertisement.swift; sourceTree = "<group>"; };
|
||||
@@ -380,6 +382,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
78F8BB4A261C50D500D9F37F /* Styles */,
|
||||
9ED4409F2C1605EF002574D1 /* OpenHaystackSettingsView.swift */,
|
||||
78286D7625E5114600F65511 /* ActivityIndicator.swift */,
|
||||
78EC226B25DBC2E40042B775 /* OpenHaystackMainView.swift */,
|
||||
78486BEE25DD711E0007ED87 /* PopUpAlertView.swift */,
|
||||
@@ -644,6 +647,7 @@
|
||||
7821DAD325F7C39A0054DC33 /* ESP32InstallSheet.swift in Sources */,
|
||||
781EB3F125DAD7EA00FEAA19 /* FindMyKeyDecoder.swift in Sources */,
|
||||
787D8AC125DECD3C00148766 /* AccessoryController.swift in Sources */,
|
||||
9ED440A02C1605EF002574D1 /* OpenHaystackSettingsView.swift in Sources */,
|
||||
78023CAB25F7767000B083EF /* ESP32Controller.swift in Sources */,
|
||||
F12D5A6025FA79FA00CBBA09 /* Advertisement.swift in Sources */,
|
||||
781EB3F225DAD7EA00FEAA19 /* OpenHaystackApp.swift in Sources */,
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
{
|
||||
"originHash" : "bfeb00ee66eb6db71ff8535b5ea7585725e9fe73d97f066170be55b745d346e9",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "swift-atomics",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-atomics.git",
|
||||
"state" : {
|
||||
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
|
||||
"version" : "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-collections",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-collections.git",
|
||||
"state" : {
|
||||
"revision" : "ee97538f5b81ae89698fd95938896dec5217b148",
|
||||
"version" : "1.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-crypto",
|
||||
"kind" : "remoteSourceControl",
|
||||
@@ -14,8 +33,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio.git",
|
||||
"state" : {
|
||||
"revision" : "124119f0bb12384cef35aa041d7c3a686108722d",
|
||||
"version" : "2.40.0"
|
||||
"revision" : "9428f62793696d9a0cc1f26a63f63bb31da0516d",
|
||||
"version" : "2.66.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -23,10 +42,19 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-ssl",
|
||||
"state" : {
|
||||
"revision" : "c30c680c78c99afdabf84805a83c8745387c4ac7",
|
||||
"version" : "2.20.2"
|
||||
"revision" : "2b09805797f21c380f7dc9bedaab3157c5508efb",
|
||||
"version" : "2.27.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-system",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-system.git",
|
||||
"state" : {
|
||||
"revision" : "f9266c85189c2751589a50ea5aec72799797e471",
|
||||
"version" : "1.3.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
"version" : 3
|
||||
}
|
||||
|
||||
@@ -118,8 +118,6 @@ public class AnisetteDataManager: NSObject {
|
||||
|
||||
guard let anisetteData = AOSUtilities.retrieveOTPHeadersForDSID("-2") else { throw AnisetteDataError.aosKitFailure }
|
||||
|
||||
let dateFormatter = ISO8601DateFormatter()
|
||||
|
||||
guard let machineID = anisetteData["X-Apple-MD-M"] as? String,
|
||||
let otp = anisetteData["X-Apple-MD"] as? String,
|
||||
let deviceId = AOSUtilities.machineUDID,
|
||||
|
||||
@@ -148,6 +148,10 @@ class FindMyController: ObservableObject {
|
||||
|
||||
} catch {
|
||||
print("Failed with error \(error)")
|
||||
if jsonData.isEmpty {
|
||||
print("Empty response, consider updating your Search Party Token")
|
||||
completion(FindMyErrors.invalidSearchPartyToken)
|
||||
}
|
||||
devices[deviceIndex].reports = []
|
||||
}
|
||||
fetchReportGroup.leave()
|
||||
@@ -241,4 +245,5 @@ class FindMyController: ObservableObject {
|
||||
enum FindMyErrors: Error {
|
||||
case decodingPlistFailed(message: String)
|
||||
case objectReleased
|
||||
case invalidSearchPartyToken
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import OSLog
|
||||
import SwiftUI
|
||||
|
||||
class AccessoryController: ObservableObject {
|
||||
@AppStorage("searchPartyToken") private var searchPartyToken: String = ""
|
||||
@Published var accessories: [Accessory]
|
||||
var selfObserver: AnyCancellable?
|
||||
var listElementsObserver = [AnyCancellable]()
|
||||
@@ -244,10 +245,8 @@ class AccessoryController: ObservableObject {
|
||||
case .failure(_):
|
||||
completion(.failure(.activatePlugin))
|
||||
case .success(let accountData):
|
||||
|
||||
guard let token = accountData.searchPartyToken,
|
||||
token.isEmpty == false
|
||||
else {
|
||||
let token = accountData.searchPartyToken ?? self.searchPartyToken.data(using: .utf8) ?? Data()
|
||||
if token.isEmpty {
|
||||
completion(.failure(.searchPartyToken))
|
||||
return
|
||||
}
|
||||
@@ -256,7 +255,12 @@ class AccessoryController: ObservableObject {
|
||||
switch result {
|
||||
case .failure(let error):
|
||||
os_log(.error, "Downloading reports failed %@", error.localizedDescription)
|
||||
completion(.failure(.downloadingReportsFailed))
|
||||
switch error {
|
||||
case FindMyErrors.invalidSearchPartyToken:
|
||||
completion(.failure(.invalidSearchPartyToken))
|
||||
default:
|
||||
completion(.failure(.downloadingReportsFailed))
|
||||
}
|
||||
case .success(let devices):
|
||||
let reports = devices.compactMap({ $0.reports }).flatMap({ $0 })
|
||||
if reports.isEmpty {
|
||||
|
||||
@@ -38,6 +38,9 @@ struct OpenHaystackMainView: View {
|
||||
|
||||
@State var showESP32DeploySheet = false
|
||||
|
||||
@AppStorage("searchPartyToken") private var settingsSPToken: String?
|
||||
@AppStorage("useMailPlugin") private var settingsUseMailPlugin: Bool = false
|
||||
|
||||
var body: some View {
|
||||
|
||||
NavigationView {
|
||||
@@ -135,7 +138,7 @@ struct OpenHaystackMainView: View {
|
||||
|
||||
Button(
|
||||
action: {
|
||||
if !self.mailPluginIsActive {
|
||||
if self.settingsUseMailPlugin && !self.mailPluginIsActive {
|
||||
self.showMailPlugInPopover.toggle()
|
||||
self.checkPluginIsRunning(silent: true, nil)
|
||||
} else {
|
||||
@@ -174,17 +177,26 @@ struct OpenHaystackMainView: View {
|
||||
return
|
||||
}
|
||||
|
||||
let pluginManager = MailPluginManager()
|
||||
|
||||
// Check if the plugin is installed
|
||||
if pluginManager.isMailPluginInstalled == false {
|
||||
// Install the mail plugin
|
||||
self.alertType = .activatePlugin
|
||||
self.checkPluginIsRunning(silent: true, nil)
|
||||
} else {
|
||||
self.checkPluginIsRunning(nil)
|
||||
/// Checks if the search party token was set in the settings. If true the plugin is also not needed
|
||||
if let tokenString = self.settingsSPToken {
|
||||
self.searchPartyToken = tokenString
|
||||
return
|
||||
}
|
||||
|
||||
/// Uses mail plugin if enabled in settings
|
||||
if self.settingsUseMailPlugin {
|
||||
let pluginManager = MailPluginManager()
|
||||
// Check if the plugin is installed
|
||||
if pluginManager.isMailPluginInstalled == false {
|
||||
// Install the mail plugin
|
||||
self.alertType = .activatePlugin
|
||||
self.checkPluginIsRunning(silent: true, nil)
|
||||
} else {
|
||||
self.checkPluginIsRunning(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Download the location reports for all current accessories. Shows an error if something fails, like plug-in is missing
|
||||
@@ -308,7 +320,19 @@ struct OpenHaystackMainView: View {
|
||||
title: Text("Add the search party token"),
|
||||
message: Text(
|
||||
"""
|
||||
Please paste the search party token below after copying itfrom the macOS Keychain.
|
||||
Please paste the search party token in the settings after copying it from the macOS Keychain.
|
||||
The item that contains the key can be found by searching for:
|
||||
com.apple.account.DeviceLocator.search-party-token
|
||||
"""
|
||||
),
|
||||
dismissButton: Alert.Button.okay())
|
||||
case .invalidSearchPartyToken:
|
||||
return Alert(
|
||||
title: Text("Invalid search party token"),
|
||||
message: Text(
|
||||
"""
|
||||
The request returned an empty result, this is probably due to an invalid search party token.
|
||||
Please consider updating your search party token in the settings after copying it from the macOS Keychain.
|
||||
The item that contains the key can be found by searching for:
|
||||
com.apple.account.DeviceLocator.search-party-token
|
||||
"""
|
||||
@@ -388,6 +412,7 @@ struct OpenHaystackMainView: View {
|
||||
|
||||
case keyError
|
||||
case searchPartyToken
|
||||
case invalidSearchPartyToken
|
||||
case deployFailed
|
||||
case nrfDeployFailed
|
||||
case deployedSuccessfully
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// OpenHaystack – Tracking personal Bluetooth devices via Apple's Find My network
|
||||
//
|
||||
// Copyright © 2024 Secure Mobile Networking Lab (SEEMOO)
|
||||
// Copyright © 2024 The Open Wireless Link Project
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct OpenHaystackSettingsView: View {
|
||||
var body: some View {
|
||||
TabView {
|
||||
GeneralSettingsView()
|
||||
.tabItem {
|
||||
Label("General", systemImage: "gear")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct GeneralSettingsView: View {
|
||||
@AppStorage("useMailPlugin") private var useMailPlugin = false
|
||||
@AppStorage("searchPartyToken") private var searchPartyToken = ""
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Toggle("Use Apple Mail Plugin (only works on macOS 13 and lower)", isOn: $useMailPlugin)
|
||||
TextField("Search Party Token", text: $searchPartyToken)
|
||||
}
|
||||
.padding(20)
|
||||
.frame(width: 600, height: 200)
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,11 @@ struct OpenHaystackApp: App {
|
||||
.commands {
|
||||
SidebarCommands()
|
||||
}
|
||||
#if os(macOS)
|
||||
Settings {
|
||||
OpenHaystackSettingsView()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
func checkForUpdates() {
|
||||
|
||||
Reference in New Issue
Block a user