mirror of
https://github.com/seemoo-lab/openhaystack.git
synced 2026-08-23 21:46:15 +00:00
Complete rebase
This commit is contained in:
@@ -97,7 +97,7 @@ public class AnisetteDataManager: NSObject {
|
||||
"X-Apple-I-MD": data.oneTimePassword,
|
||||
"X-Apple-I-TimeZone": String(data.timeZone.abbreviation() ?? "UTC"),
|
||||
"X-Apple-I-Client-Time": ISO8601DateFormatter().string(from: data.date),
|
||||
"X-Apple-I-MD-RINFO": String(data.routingInfo)
|
||||
"X-Apple-I-MD-RINFO": String(data.routingInfo),
|
||||
] as [AnyHashable: Any])
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,8 @@ extension AnisetteDataManager {
|
||||
guard let userInfo = notification.userInfo, let requestUUID = userInfo["requestUUID"] as? String else { return }
|
||||
|
||||
if let archivedAnisetteData = userInfo["anisetteData"] as? Data,
|
||||
let appleAccountData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: AppleAccountData.self, from: archivedAnisetteData) {
|
||||
let appleAccountData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: AppleAccountData.self, from: archivedAnisetteData)
|
||||
{
|
||||
if let range = appleAccountData.deviceDescription.lowercased().range(of: "(com.apple.mail") {
|
||||
var adjustedDescription = appleAccountData.deviceDescription[..<range.lowerBound]
|
||||
adjustedDescription += "(com.apple.dt.Xcode/3594.4.19)>"
|
||||
@@ -128,7 +129,8 @@ extension AnisetteDataManager {
|
||||
guard let userInfo = notification.userInfo, let requestUUID = userInfo["requestUUID"] as? String else { return }
|
||||
|
||||
if let archivedAnisetteData = userInfo["anisetteData"] as? Data,
|
||||
let anisetteData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ALTAnisetteData.self, from: archivedAnisetteData) {
|
||||
let anisetteData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ALTAnisetteData.self, from: archivedAnisetteData)
|
||||
{
|
||||
if let range = anisetteData.deviceDescription.lowercased().range(of: "(com.apple.mail") {
|
||||
var adjustedDescription = anisetteData.deviceDescription[..<range.lowerBound]
|
||||
adjustedDescription += "(com.apple.dt.Xcode/3594.4.19)>"
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import OSLog
|
||||
import SwiftUI
|
||||
|
||||
class FindMyController: ObservableObject {
|
||||
static let shared = FindMyController()
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
class AccessoryController: ObservableObject {
|
||||
static let shared = AccessoryController()
|
||||
|
||||
@@ -16,9 +16,9 @@ struct ESP32Controller {
|
||||
/// Tries to find the port / path at which the ESP32 module is attached
|
||||
static func findPort() -> [URL] {
|
||||
// List all ports
|
||||
let ports = try? FileManager.default.contentsOfDirectory(atPath: "/dev").filter({$0.contains("cu.")})
|
||||
let ports = try? FileManager.default.contentsOfDirectory(atPath: "/dev").filter({ $0.contains("cu.") })
|
||||
|
||||
let portURLs = ports?.map({URL(fileURLWithPath: "/dev/\($0)")})
|
||||
let portURLs = ports?.map({ URL(fileURLWithPath: "/dev/\($0)") })
|
||||
|
||||
return portURLs ?? []
|
||||
}
|
||||
@@ -33,7 +33,7 @@ struct ESP32Controller {
|
||||
|
||||
try? FileManager.default.createDirectory(atPath: temp, withIntermediateDirectories: false, attributes: nil)
|
||||
|
||||
guard let espDirectory = espFirmwareDirectory else {return}
|
||||
guard let espDirectory = espFirmwareDirectory else { return }
|
||||
|
||||
try FileManager.default.copyFolder(from: espDirectory, to: urlTemp)
|
||||
let scriptPath = urlTemp.appendingPathComponent("flash_esp32.sh")
|
||||
@@ -61,6 +61,6 @@ struct ESP32Controller {
|
||||
enum FirmwareFlashError: Error {
|
||||
/// Missing files for flashing
|
||||
case notFound
|
||||
/// Flashing / writing failed
|
||||
/// Flashing / writing failed
|
||||
case flashFailed
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ struct KeychainController {
|
||||
kSecAttrLabel: "FindMyAccessories",
|
||||
kSecAttrService: "SEEMOO-FINDMY",
|
||||
kSecMatchLimit: kSecMatchLimitOne,
|
||||
kSecReturnData: true
|
||||
kSecReturnData: true,
|
||||
]
|
||||
|
||||
if test {
|
||||
@@ -49,7 +49,7 @@ struct KeychainController {
|
||||
kSecClass: kSecClassGenericPassword,
|
||||
kSecAttrLabel: "FindMyAccessories",
|
||||
kSecAttrService: "SEEMOO-FINDMY",
|
||||
kSecValueData: try PropertyListEncoder().encode(accessories)
|
||||
kSecValueData: try PropertyListEncoder().encode(accessories),
|
||||
]
|
||||
|
||||
if test {
|
||||
@@ -63,7 +63,7 @@ struct KeychainController {
|
||||
var query: [CFString: Any] = [
|
||||
kSecClass: kSecClassGenericPassword,
|
||||
kSecAttrLabel: "FindMyAccessories",
|
||||
kSecAttrService: "SEEMOO-FINDMY"
|
||||
kSecAttrService: "SEEMOO-FINDMY",
|
||||
]
|
||||
|
||||
if test {
|
||||
|
||||
@@ -44,7 +44,8 @@ class Accessory: ObservableObject, Codable, Identifiable, Equatable, Hashable {
|
||||
|
||||
if var colorComponents = try? container.decode([CGFloat].self, forKey: .colorComponents),
|
||||
let spaceName = try? container.decode(String.self, forKey: .colorSpaceName),
|
||||
let cgColor = CGColor(colorSpace: CGColorSpace(name: spaceName as CFString)!, components: &colorComponents) {
|
||||
let cgColor = CGColor(colorSpace: CGColorSpace(name: spaceName as CFString)!, components: &colorComponents)
|
||||
{
|
||||
self.color = Color(cgColor)
|
||||
} else {
|
||||
self.color = Color.white
|
||||
@@ -60,7 +61,8 @@ class Accessory: ObservableObject, Codable, Identifiable, Equatable, Hashable {
|
||||
try container.encode(self.icon, forKey: .icon)
|
||||
|
||||
if let colorComponents = self.color.cgColor?.components,
|
||||
let colorSpace = self.color.cgColor?.colorSpace?.name {
|
||||
let colorSpace = self.color.cgColor?.colorSpace?.name
|
||||
{
|
||||
try container.encode(colorComponents, forKey: .colorComponents)
|
||||
try container.encode(colorSpace as String, forKey: .colorSpaceName)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
// Copyright © 2021 SEEMOO - TU Darmstadt. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import OSLog
|
||||
import SwiftUI
|
||||
|
||||
struct ESP32InstallSheet: View {
|
||||
@Binding var accessory: Accessory?
|
||||
@@ -44,13 +44,17 @@ struct ESP32InstallSheet: View {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button("Reload ports", action: {
|
||||
self.detectedPorts = ESP32Controller.findPort()
|
||||
})
|
||||
Button(
|
||||
"Reload ports",
|
||||
action: {
|
||||
self.detectedPorts = ESP32Controller.findPort()
|
||||
})
|
||||
|
||||
Button("Cancel", action: {
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
})
|
||||
Button(
|
||||
"Cancel",
|
||||
action: {
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,20 +63,23 @@ struct ESP32InstallSheet: View {
|
||||
ScrollView {
|
||||
VStack(spacing: 4) {
|
||||
ForEach(0..<self.detectedPorts.count, id: \.self) { portIdx in
|
||||
Button(action: {
|
||||
if let accessory = self.accessory {
|
||||
// Flash selected module
|
||||
self.deployAccessoryToESP32(accessory: accessory, to: self.detectedPorts[portIdx])
|
||||
}
|
||||
}, label: {
|
||||
HStack {
|
||||
Text(self.detectedPorts[portIdx].path)
|
||||
.padding(4)
|
||||
Spacer()
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
Button(
|
||||
action: {
|
||||
if let accessory = self.accessory {
|
||||
// Flash selected module
|
||||
self.deployAccessoryToESP32(accessory: accessory, to: self.detectedPorts[portIdx])
|
||||
}
|
||||
},
|
||||
label: {
|
||||
HStack {
|
||||
Text(self.detectedPorts[portIdx].path)
|
||||
.padding(4)
|
||||
Spacer()
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
|
||||
})
|
||||
}
|
||||
)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
}
|
||||
@@ -98,19 +105,21 @@ struct ESP32InstallSheet: View {
|
||||
func deployAccessoryToESP32(accessory: Accessory, to port: URL) {
|
||||
do {
|
||||
self.isFlashing = true
|
||||
try ESP32Controller.flashToESP32(accessory: accessory, port: port, completion: { result in
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
try ESP32Controller.flashToESP32(
|
||||
accessory: accessory, port: port,
|
||||
completion: { result in
|
||||
presentationMode.wrappedValue.dismiss()
|
||||
|
||||
self.isFlashing = false
|
||||
switch result {
|
||||
case .success(_):
|
||||
self.alertType = .deployedSuccessfully
|
||||
case .failure(let error):
|
||||
os_log(.error, "Flashing to ESP32 failed %@", String(describing: error))
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
self.alertType = .deployFailed
|
||||
}
|
||||
})
|
||||
self.isFlashing = false
|
||||
switch result {
|
||||
case .success:
|
||||
self.alertType = .deployedSuccessfully
|
||||
case .failure(let error):
|
||||
os_log(.error, "Flashing to ESP32 failed %@", String(describing: error))
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
self.alertType = .deployFailed
|
||||
}
|
||||
})
|
||||
} catch {
|
||||
os_log(.error, "Execution of script failed %@", String(describing: error))
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
|
||||
@@ -41,9 +41,17 @@ struct ManageAccessoriesView: View {
|
||||
self.accessoryList
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: self.$showESP32DeploySheet, content: {
|
||||
ESP32InstallSheet(accessory: self.$accessoryToDeploy, alertType: self.$alertType)
|
||||
.toolbar(content: {
|
||||
Spacer()
|
||||
Button(action: self.addAccessory) {
|
||||
Label("Add accessory", systemImage: "plus")
|
||||
}
|
||||
})
|
||||
.sheet(
|
||||
isPresented: self.$showESP32DeploySheet,
|
||||
content: {
|
||||
ESP32InstallSheet(accessory: self.$accessoryToDeploy, alertType: self.$alertType)
|
||||
})
|
||||
}
|
||||
|
||||
/// Accessory List view.
|
||||
@@ -65,10 +73,11 @@ struct ManageAccessoriesView: View {
|
||||
),
|
||||
alertType: self.$alertType,
|
||||
delete: self.delete(accessory:),
|
||||
deployAccessoryToMicrobit: self.deployAccessoryToMicrobit(accessory:),
|
||||
deployAccessoryToMicrobit: self.deploy(accessory:),
|
||||
zoomOn: { self.focusedAccessory = $0 })
|
||||
}
|
||||
.listStyle(SidebarListStyle())
|
||||
|
||||
}
|
||||
|
||||
/// Delete an accessory from the list of accessories.
|
||||
@@ -91,9 +100,7 @@ struct ManageAccessoriesView: View {
|
||||
self.keyName = ""
|
||||
|
||||
do {
|
||||
let accessory = try self.accessoryController.addAccessory(with: keyName, color: self.accessoryColor, icon: self.selectedIcon)
|
||||
self.deploy(accessory: accessory)
|
||||
|
||||
_ = try self.accessoryController.addAccessory(with: keyName, color: self.accessoryColor, icon: self.selectedIcon)
|
||||
} catch {
|
||||
self.alertType = .keyError
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ struct OpenHaystackMainView: View {
|
||||
@State var searchPartyTokenLoaded = false
|
||||
@State var mapType: MKMapType = .standard
|
||||
@State var isLoading = false
|
||||
@State var focusedAccessory: Accessory? = nil
|
||||
@State var focusedAccessory: Accessory?
|
||||
@State var accessoryToDeploy: Accessory?
|
||||
|
||||
@State var showESP32DeploySheet = false
|
||||
@@ -38,13 +38,8 @@ struct OpenHaystackMainView: View {
|
||||
alertType: self.$alertType,
|
||||
focusedAccessory: self.$focusedAccessory,
|
||||
accessoryToDeploy: self.$accessoryToDeploy,
|
||||
showESP32DeploySheet: self.$showESP32DeploySheet)
|
||||
.toolbar(content: {
|
||||
Spacer()
|
||||
Button(action: self.addAccessory) {
|
||||
Label("Add accessory", systemImage: "plus")
|
||||
}
|
||||
})
|
||||
showESP32DeploySheet: self.$showESP32DeploySheet
|
||||
)
|
||||
.navigationTitle(self.focusedAccessory?.name ?? "OpenHaystack")
|
||||
|
||||
ZStack {
|
||||
@@ -137,7 +132,8 @@ struct OpenHaystackMainView: View {
|
||||
/// Checks if the search party token can be fetched without the Mail Plugin. If true the plugin is not needed for this environment. (e.g. when SIP is disabled)
|
||||
let reportsFetcher = ReportsFetcher()
|
||||
if let token = reportsFetcher.fetchSearchpartyToken(),
|
||||
let tokenString = String(data: token, encoding: .ascii) {
|
||||
let tokenString = String(data: token, encoding: .ascii)
|
||||
{
|
||||
self.searchPartyToken = tokenString
|
||||
return
|
||||
}
|
||||
@@ -334,16 +330,19 @@ struct OpenHaystackMainView: View {
|
||||
self.downloadPlugin()
|
||||
}), secondaryButton: .cancel())
|
||||
case .selectDepoyTarget:
|
||||
let microbitButton = Alert.Button.default(Text("Microbit"), action: {self.deployAccessoryToMicrobit(accessory: self.accessoryToDeploy!)})
|
||||
let microbitButton = Alert.Button.default(Text("Microbit"), action: { self.deployAccessoryToMicrobit(accessory: self.accessoryToDeploy!) })
|
||||
|
||||
let esp32Button = Alert.Button.default(Text("ESP32"), action: {
|
||||
self.showESP32DeploySheet = true
|
||||
})
|
||||
let esp32Button = Alert.Button.default(
|
||||
Text("ESP32"),
|
||||
action: {
|
||||
self.showESP32DeploySheet = true
|
||||
})
|
||||
|
||||
return Alert(title: Text("Select target"),
|
||||
message: Text("Please select to which device you want to deploy"),
|
||||
primaryButton: microbitButton,
|
||||
secondaryButton: esp32Button)
|
||||
return Alert(
|
||||
title: Text("Select target"),
|
||||
message: Text("Please select to which device you want to deploy"),
|
||||
primaryButton: microbitButton,
|
||||
secondaryButton: esp32Button)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
@testable import OpenHaystack
|
||||
|
||||
class MicrocontrollerTests: XCTestCase {
|
||||
@@ -88,11 +89,11 @@ class MicrocontrollerTests: XCTestCase {
|
||||
func testESP32Deploy() throws {
|
||||
let accessory = try Accessory(name: "Sample")
|
||||
let expect = expectation(description: "ESP32 Flash")
|
||||
let port = ESP32Controller.findPort().first(where: {$0.absoluteString.contains("usb")})!
|
||||
let port = ESP32Controller.findPort().first(where: { $0.absoluteString.contains("usb") })!
|
||||
try ESP32Controller.flashToESP32(accessory: accessory, port: port) { result in
|
||||
expect.fulfill()
|
||||
switch result {
|
||||
case .success(_):
|
||||
case .success:
|
||||
break
|
||||
case .failure(let error):
|
||||
XCTFail(error.localizedDescription)
|
||||
|
||||
Reference in New Issue
Block a user