🔴 Critical: - DXSmartProvisioner: complete rewrite to match Android's new SDK protocol - Writes to FFE2 (not FFE1) using 4E4F protocol packets - Correct command IDs: 0x74 UUID, 0x75 Major, 0x76 Minor, 0x77 RSSI, 0x78 AdvInt, 0x79 TxPower, 0x60 Save - Frame selection (0x11/0x12) + frame type (0x62 iBeacon) - Old SDK fallback (0x36-0x43 via FFE1 with 555555 re-auth per command) - Auth timing: 100ms delays (was 500ms, matches Android SDK) - BeaconShardPool: replaced 71 pattern UUIDs with exact 64 from Android 🟡 Warnings: - BlueCharmProvisioner: 3 fallback write methods matching Android (FEA3 direct → FEA1 raw → FEA1 indexed), legacy FFF0 support, added "minew123" and "bc04p" passwords (5 total, was 3) - BeaconBanList: added 4 missing prefixes (8492E75F, A0B13730, EBEFD083, B5B182C7), full UUID ban list, getBanReason() helper - BLEManager: documented MAC OUI limitation (48:87:2D not available on iOS via CoreBluetooth) 🔵 Info: - APIClient: added get_beacon_config endpoint for server-configured values - ScanView: unknown beacon type now tries KBeacon→DXSmart→BlueCharm fallback chain via new FallbackProvisioner - DXSmartProvisioner: added readFrame2() for post-write verification Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
57 lines
2.3 KiB
Swift
57 lines
2.3 KiB
Swift
import Foundation
|
|
|
|
/// Factory-default UUIDs that indicate an unconfigured beacon
|
|
/// Matches Android BeaconBanList.kt exactly
|
|
enum BeaconBanList {
|
|
|
|
/// UUID prefixes (first 8 hex chars) that are factory defaults
|
|
/// Key = uppercase prefix, Value = reason
|
|
private static let bannedPrefixes: [String: String] = [
|
|
"E2C56DB5": "Apple AirLocate / Minew factory default",
|
|
"F7826DA6": "Kontakt.io factory default",
|
|
"2F234454": "Radius Networks default",
|
|
"B9407F30": "Estimote factory default",
|
|
"FDA50693": "Generic bulk / Feasycom factory default",
|
|
"74278BDA": "Generic bulk manufacturer default",
|
|
"8492E75F": "Generic bulk manufacturer default",
|
|
"A0B13730": "Generic bulk manufacturer default",
|
|
"EBEFD083": "JAALEE factory default",
|
|
"B5B182C7": "April Brother factory default",
|
|
"00000000": "Unconfigured / zeroed UUID",
|
|
"FFFFFFFF": "Unconfigured / max UUID",
|
|
]
|
|
|
|
/// Full UUIDs that are known defaults (exact match on 32-char uppercase hex, no dashes)
|
|
private static let bannedFullUUIDs: [String: String] = [
|
|
"E2C56DB5DFFB48D2B060D0F5A71096E0": "Apple AirLocate sample UUID",
|
|
"B9407F30F5F8466EAFF925556B57FE6D": "Estimote factory default",
|
|
"2F234454CF6D4A0FADF2F4911BA9FFA6": "Radius Networks default",
|
|
"FDA50693A4E24FB1AFCFC6EB07647825": "Generic Chinese bulk default",
|
|
"74278BDAB64445208F0C720EAF059935": "Generic bulk default",
|
|
"00000000000000000000000000000000": "Zeroed UUID — unconfigured hardware",
|
|
]
|
|
|
|
/// Check if a UUID is a factory default
|
|
static func isBanned(_ uuid: String) -> Bool {
|
|
let normalized = uuid.normalizedUUID
|
|
|
|
// Check full UUID match
|
|
if bannedFullUUIDs[normalized] != nil { return true }
|
|
|
|
// Check prefix match
|
|
let prefix = String(normalized.prefix(8))
|
|
return bannedPrefixes[prefix] != nil
|
|
}
|
|
|
|
/// Get the reason a UUID is banned, or nil if not banned
|
|
static func getBanReason(_ uuid: String) -> String? {
|
|
let normalized = uuid.normalizedUUID
|
|
|
|
// Check full UUID match first
|
|
if let reason = bannedFullUUIDs[normalized] { return reason }
|
|
|
|
// Check prefix
|
|
let prefix = String(normalized.prefix(8))
|
|
return bannedPrefixes[prefix]
|
|
}
|
|
}
|