Merge pull request #1390 from justcallmekoko/develop

Add backend for FindMy Live
This commit is contained in:
Just Call Me Koko
2026-07-18 11:19:49 -04:00
committed by GitHub
3 changed files with 334 additions and 124 deletions
+11 -8
View File
@@ -339,6 +339,7 @@ void MenuFunctions::main(uint32_t currentTime)
(wifi_scan_obj.currentScanMode == BT_SCAN_ALL) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_FOX_HUNT) ||
(wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) ||
(wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_RAYBAN) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON) ||
@@ -407,6 +408,7 @@ void MenuFunctions::main(uint32_t currentTime)
(wifi_scan_obj.currentScanMode == WIFI_SCAN_DISPLAY_AP_INFO) ||
(wifi_scan_obj.currentScanMode == WIFI_SCAN_EVIL_PORTAL) ||
(wifi_scan_obj.currentScanMode == WIFI_SCAN_SIG_STREN) ||
(wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) ||
(wifi_scan_obj.currentScanMode == WIFI_SCAN_AP_STA) ||
(wifi_scan_obj.currentScanMode == WIFI_PING_SCAN) ||
(wifi_scan_obj.currentScanMode == WIFI_ARP_SCAN) ||
@@ -3205,17 +3207,17 @@ void MenuFunctions::RunSetup()
// Clear nodes and add back button
wifiAPMenu.list->clear();
this->addNodes(&wifiAPMenu, text09, TFT_LIGHTGREY, 0, [this]() {
this->addNodes(&wifiAPMenu, text09, TFTLIGHTGREY, 0, [this]() {
this->changeMenu(wifiAPMenu.parentMenu, true);
});
// Add buttons for all airtags
// Find out how big our menu is going to be
int menu_limit;
if (airtags->size() <= BUTTON_ARRAY_LEN)
menu_limit = airtags->size();
else
menu_limit = BUTTON_ARRAY_LEN;
/*this->addNodes(&wifiAPMenu, "Live", TFTMAGENTA, 0, [this]() {
display_obj.clearScreen();
this->drawStatusBar();
wifi_scan_obj.StartScan(BT_ATTACK_FINDMY_LIVE, TFT_RED);
});*/
int menu_limit = airtags->size();
// Create the menu nodes for all of the list items
for (int i = 0; i < menu_limit; i++) {
@@ -3224,6 +3226,7 @@ void MenuFunctions::RunSetup()
this->addNodes(&wifiAPMenu, node_name.c_str(), node_color, BLUETOOTH, [this, i](){
AirTag new_at = airtags->get(i);
new_at.selected = true;
new_at.connectable = true;
airtags->set(i, new_at);
+306 -113
View File
@@ -314,7 +314,60 @@ extern "C" {
String display_string = "";
if ((wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) ||
if (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) {
if (connectionPending) {
wifi_scan_obj.bt_cb_busy = false;
return;
}
#ifndef HAS_NIMBLE_2
uint8_t* payLoad = advertisedDevice->getPayload();
size_t len = advertisedDevice->getPayloadLength();
if (!payLoad) {
wifi_scan_obj.bt_cb_busy = false;
return;
}
#else
const std::vector<unsigned char>& payLoad = advertisedDevice->getPayload();
size_t len = payLoad.size();
#endif
bool match = false;
if (len >= 4) {
for (size_t i = 0; i <= len - 4; i++) {
if (payLoad[i] == 0x1E && payLoad[i+1] == 0xFF && payLoad[i+2] == 0x4C && payLoad[i+3] == 0x00) {
match = true;
break;
}
if (payLoad[i] == 0x4C && payLoad[i+1] == 0x00 && payLoad[i+2] == 0x12) {
match = true;
break;
}
}
} else {
wifi_scan_obj.bt_cb_busy = false;
return;
}
bool is_fmna = false;
bool is_dult = false;
if (advertisedDevice->isAdvertisingService(FMNA_SERVICE_UUID)) {
is_fmna = true;
}
else if (advertisedDevice->isAdvertisingService(DULT_SERVICE_UUID)) {
is_dult = true;
}
if ((match) || (is_fmna) || (is_dult)) {
pendingAddress = advertisedDevice->getAddress();
connectionPending = true;
wifi_scan_obj.bt_cb_busy = false;
return;
}
}
else if ((wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON)) {
//Serial.println("Getting payload length...");
//Serial.flush();
@@ -986,7 +1039,61 @@ extern "C" {
String display_string = "";
if ((wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) ||
if (wifi_scan_obj.currentScanMode == BT_ATTACK_FINDMY_LIVE) {
if (connectionPending) {
wifi_scan_obj.bt_cb_busy = false;
return;
}
#ifndef HAS_NIMBLE_2
uint8_t* payLoad = advertisedDevice->getPayload();
size_t len = advertisedDevice->getPayloadLength();
if (!payLoad) {
wifi_scan_obj.bt_cb_busy = false;
return;
}
#else
const std::vector<unsigned char>& payLoad = advertisedDevice->getPayload();
size_t len = payLoad.size();
#endif
bool match = false;
if (len >= 4) {
for (size_t i = 0; i <= len - 4; i++) {
if (payLoad[i] == 0x1E && payLoad[i+1] == 0xFF && payLoad[i+2] == 0x4C && payLoad[i+3] == 0x00) {
match = true;
break;
}
if (payLoad[i] == 0x4C && payLoad[i+1] == 0x00 && payLoad[i+2] == 0x12) {
match = true;
break;
}
}
} else {
wifi_scan_obj.bt_cb_busy = false;
return;
}
bool is_fmna = false;
bool is_dult = false;
if (advertisedDevice->isAdvertisingService(FMNA_SERVICE_UUID)) {
is_fmna = true;
}
else if (advertisedDevice->isAdvertisingService(DULT_SERVICE_UUID)) {
is_dult = true;
}
if ((match) || (is_fmna) || (is_dult)) {
pendingAddress = advertisedDevice->getAddress();
Serial.println("Detected " + String(pendingAddress.toString().c_str()));
connectionPending = true;
wifi_scan_obj.bt_cb_busy = false;
return;
}
}
else if ((wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG) ||
(wifi_scan_obj.currentScanMode == BT_SCAN_AIRTAG_MON)) {
#ifndef HAS_NIMBLE_2
uint8_t* payLoad = advertisedDevice->getPayload();
@@ -2261,6 +2368,11 @@ void WiFiScan::StartScan(uint8_t scan_mode, uint16_t color) {
RunBluetoothScan(scan_mode, color);
#endif
}
else if (scan_mode == BT_ATTACK_FINDMY_LIVE) {
#ifdef HAS_BT
this->RunFindMyLive(scan_mode, color);
#endif
}
else if ((scan_mode == BT_ATTACK_SOUR_APPLE) ||
(scan_mode == BT_ATTACK_APPLE_JUICE)) {
#ifdef HAS_BT
@@ -2634,6 +2746,7 @@ void WiFiScan::StopScan(uint8_t scan_mode) {
(currentScanMode == BT_SCAN_AIRTAG_MON) ||
(currentScanMode == BT_SCAN_FLIPPER) ||
(currentScanMode == BT_SCAN_FLOCK) ||
(currentScanMode == BT_ATTACK_FINDMY_LIVE) ||
(currentScanMode == BT_ATTACK_SOUR_APPLE) ||
(currentScanMode == BT_ATTACK_APPLE_JUICE) ||
(currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
@@ -4586,12 +4699,18 @@ int WiFiScan::connectAndProcessTracker(NimBLEAddress& address) {
Serial.println(address.toString().c_str());
nimbleClient->setConnectTimeout(5000);
nimbleClient->setConnectTimeout(15000);
if (!nimbleClient->connect(address, true, false, true)) {
Serial.printf("Connection failed; error=%d\n", nimbleClient->getLastError());
Serial.printf(
"connected=%d lastError=%d\n",
nimbleClient->isConnected(),
nimbleClient->getLastError()
);
return -1;
//return -1;
}
bool hasAirTagService = false;
@@ -4885,6 +5004,119 @@ bool WiFiScan::sendAirtagSoundCommand(NimBLEClient* currentClient) {
return false;
}
bool WiFiScan::backendFindMySound(NimBLEAddress& address, bool gui) {
bool send_success = false;
int device_type = this->connectAndProcessTracker(address);
if (device_type >= 0) {
Serial.println("Connected to " + String(address.toString().c_str()));
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Connected");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
if (device_type == IS_AIRTAG) {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: Airtag");
#endif
send_success = this->sendAirtagSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send AT cmd");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
else if (device_type == IS_FMNA) {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: FMNA");
#endif
send_success = this->sendFmnaSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send FMNA cmd");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
else {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: DULT");
#endif
send_success = this->sendDultSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send DULT cmd");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to connect");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
if (nimbleClient != nullptr) {
if (nimbleClient->isConnected()) {
Serial.println("Disconnecting locally...");
nimbleClient->disconnect();
}
NimBLEDevice::deleteClient(nimbleClient);
nimbleClient = nullptr;
}
NimBLEDevice::deinit(true);
return send_success;
}
bool WiFiScan::executeFindMySound(bool gui) {
bool send_success = false;
bool selected = false;
@@ -4910,121 +5142,59 @@ bool WiFiScan::executeFindMySound(bool gui) {
selected = true;
uint8_t addr[6];
convertMacStringToUint8(airtag.mac, addr);
int device_type = this->connectAndProcessTracker(airtag.device_address);
if (device_type >= 0) {
Serial.println("Connected to " + airtag.mac);
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Connected");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
if (device_type == IS_AIRTAG) {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: Airtag");
#endif
send_success = this->sendAirtagSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
else if (device_type == IS_FMNA) {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: FMNA");
#endif
send_success = this->sendFmnaSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
else {
#ifdef HAS_SCREEN
if (gui)
display_obj.tft.println("Type: DULT");
#endif
send_success = this->sendDultSoundCommand(nimbleClient);
if (send_success) {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
display_obj.tft.println("Command sent");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to send");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
}
}
} else {
#ifdef HAS_SCREEN
if (gui) {
display_obj.tft.setTextColor(TFT_RED, TFT_BLACK);
display_obj.tft.println("Failed to connect");
display_obj.tft.setTextColor(TFT_WHITE, TFT_BLACK);
}
#endif
if (!this->backendFindMySound(airtag.device_address, gui)) {
airtag.connectable = false;
airtags->set(i, airtag);
}
break;
}
}
if (nimbleClient != nullptr) {
if (nimbleClient->isConnected()) {
Serial.println("Disconnecting locally...");
nimbleClient->disconnect();
}
NimBLEDevice::deleteClient(nimbleClient);
nimbleClient = nullptr;
}
NimBLEDevice::deinit(true);
return send_success;
}
void WiFiScan::executeFindMyLive(uint32_t current_time) {
if (connectionPending && !operationInProgress) {
this->shutdownBLE();
operationInProgress = true;
connectionPending = false;
NimBLEAddress address = pendingAddress;
this->setLEDMode(MODE_ATTACK);
this->backendFindMySound(address);
operationInProgress = false;
this->initializeFindMyScan();
}
if (!connectionPending && !operationInProgress && !this->ble_initialized)
this->initializeFindMyScan();
}
void WiFiScan::initializeFindMyScan() {
NimBLEDevice::init("");
pBLEScan = NimBLEDevice::getScan();
#ifndef HAS_NIMBLE_2
pBLEScan->setAdvertisedDeviceCallbacks(new bluetoothScanAllCallback(), true);
#else
pBLEScan->setScanCallbacks(new bluetoothScanAllCallback(), true);
#endif
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(50);
pBLEScan->setWindow(30); // less or equal setInterval value
pBLEScan->setMaxResults(0);
pBLEScan->setDuplicateFilter(false);
pBLEScan->start(0, scanCompleteCB, false);
this->setLEDMode(MODE_SNIFF);
this->ble_initialized = true;
Serial.println("Initialized NimBLEDevice scan");
}
#endif
void WiFiScan::executeBLESpam(EBLEPayloadType type) {
@@ -6049,6 +6219,24 @@ void WiFiScan::RunProbeScan(uint8_t scan_mode, uint16_t color) {
initTime = millis();
}
void WiFiScan::RunFindMyLive(uint8_t scan_mode, uint16_t color) {
#ifdef HAS_BT
#ifdef HAS_SCREEN
this->setupScanDisplayArea(TFT_BLACK, color);
#ifdef HAS_FULL_SCREEN
display_obj.tft.fillRect(0,16,TFT_WIDTH,16, color);
display_obj.tft.drawCentreString("Find My Live",TFT_WIDTH / 2,16,2);
#endif
#ifdef HAS_ILI9341
display_obj.touchToExit();
#endif
display_obj.tft.setTextColor(TFT_GREEN, TFT_BLACK);
#endif
this->setLEDMode(MODE_ATTACK);
#endif
}
void WiFiScan::RunSourApple(uint8_t scan_mode, uint16_t color) {
#ifdef HAS_BT
NimBLEDevice::init("");
@@ -11419,6 +11607,11 @@ void WiFiScan::main(uint32_t currentTime)
}
this->packetRateLoop(currentTime);
}
else if (currentScanMode == BT_ATTACK_FINDMY_LIVE) {
#ifdef HAS_NIMBLE_2
this->executeFindMyLive(currentTime);
#endif
}
else if ((currentScanMode == BT_ATTACK_SWIFTPAIR_SPAM) ||
(currentScanMode == BT_ATTACK_SOUR_APPLE) ||
(currentScanMode == BT_ATTACK_APPLE_JUICE) ||
+17 -3
View File
@@ -165,6 +165,7 @@
#define WIFI_SCAN_DISPLAY_AP_INFO 83
#define BT_SCAN_FOX_HUNT 84
#define BT_FINDMY_SOUND 85
#define BT_ATTACK_FINDMY_LIVE 86
#define WIFI_ATTACK_FUNNY_BEACON 99
@@ -300,6 +301,14 @@ static const uint8_t DULT_START_SOUND_COMMAND[] = {
static const uint8_t DULT_STOP_SOUND_COMMAND[] = {
0x01, 0x03
};
static NimBLEAddress pendingAddress(
"00:00:00:00:00:00",
BLE_ADDR_PUBLIC
);
bool connectionPending = false;
bool operationInProgress = false;
#endif
#pragma pack(push, 1)
@@ -325,9 +334,10 @@ struct AirTag {
bool selected;
int8_t rssi;
uint32_t last_seen;
bool is_airtag = false;
bool is_fmna = false;
bool is_dult = false;
bool is_airtag = false;
bool is_fmna = false;
bool is_dult = false;
bool connectable = true;
#ifdef HAS_BT
NimBLEAddress device_address;
#endif
@@ -668,11 +678,13 @@ class WiFiScan
#ifdef HAS_NIMBLE_2
int connectAndProcessTracker(NimBLEAddress& address);
bool backendFindMySound(NimBLEAddress& address, bool gui = false);
bool sendAirtagSoundCommand(NimBLEClient* currentClient);
bool sendFmnaSoundCommand(NimBLEClient* currentClient);
bool sendDultSoundCommand(NimBLEClient* currentClient);
bool enableTrackerResponses(NimBLERemoteCharacteristic* characteristic);
void createNimbleClient();
void initializeFindMyScan();
#endif
bool wigleUpload(String filePath);
@@ -737,6 +749,7 @@ class WiFiScan
void broadcastCustomBeacon(uint32_t current_time, ssid custom_ssid, bool for_camera = false);
void broadcastCustomBeacon(uint32_t current_time, AccessPoint custom_ssid, int scan_mode);
void broadcastSetSSID(uint32_t current_time, const char* ESSID, uint8_t chan = 0, bool legit = false);
void executeFindMyLive(uint32_t current_time);
void RunAPScan(uint8_t scan_mode, uint16_t color);
void RunGPSNmea();
void RunPwnScan(uint8_t scan_mode, uint16_t color);
@@ -751,6 +764,7 @@ class WiFiScan
void RunPacketMonitor(uint8_t scan_mode, uint16_t color);
void RunBluetoothScan(uint8_t scan_mode, uint16_t color);
void RunSourApple(uint8_t scan_mode, uint16_t color);
void RunFindMyLive(uint8_t scan_mode, uint16_t color);
void RunSwiftpairSpam(uint8_t scan_mode, uint16_t color);
void RunEvilPortal(uint8_t scan_mode, uint16_t color);
void RunPingScan(uint8_t scan_mode, uint16_t color);