Skip to content

Commit

Permalink
Merge branch 'release/monterey'
Browse files Browse the repository at this point in the history
  • Loading branch information
ts1 committed Sep 12, 2021
2 parents 5c4db94 + e44de10 commit 3fef53d
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 8 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,5 @@ fastlane/report.xml
fastlane/screenshots

.DS_Store

/archives
8 changes: 6 additions & 2 deletions BLEUnlock.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
3D4EE4152279E94B00AF9E93 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3D4EE4142279E94B00AF9E93 /* MainMenu.xib */; };
3D600A37226CC1A40068FB7B /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3D600A35226CC1A40068FB7B /* Localizable.strings */; };
3D600A5A22701E740068FB7B /* Launcher.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3D600A4022701A5A0068FB7B /* Launcher.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3D6070E226DBC68E00EE4E48 /* LEDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D6070E126DBC68E00EE4E48 /* LEDeviceInfo.swift */; };
3D79FD7D226C335100A373C0 /* appleDeviceNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D79FD7C226C335100A373C0 /* appleDeviceNames.swift */; };
3D95379522784D550017D8B9 /* AboutBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D95379322784D550017D8B9 /* AboutBox.swift */; };
3D953797227853E20017D8B9 /* AboutBox.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3D953799227853E20017D8B9 /* AboutBox.xib */; };
Expand Down Expand Up @@ -50,6 +51,7 @@
3D600A4022701A5A0068FB7B /* Launcher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Launcher.app; sourceTree = BUILT_PRODUCTS_DIR; };
3D600A4922701A5C0068FB7B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3D600A4A22701A5C0068FB7B /* Launcher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Launcher.entitlements; sourceTree = "<group>"; };
3D6070E126DBC68E00EE4E48 /* LEDeviceInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LEDeviceInfo.swift; sourceTree = "<group>"; };
3D79FD7C226C335100A373C0 /* appleDeviceNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = appleDeviceNames.swift; sourceTree = "<group>"; };
3D95379322784D550017D8B9 /* AboutBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutBox.swift; sourceTree = "<group>"; };
3D953798227853E20017D8B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AboutBox.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -129,6 +131,7 @@
3D953799227853E20017D8B9 /* AboutBox.xib */,
3D600A35226CC1A40068FB7B /* Localizable.strings */,
3DD4B665226C1DF200451B7B /* BLE.swift */,
3D6070E126DBC68E00EE4E48 /* LEDeviceInfo.swift */,
3DD4B653226C1C3200451B7B /* AppDelegate.swift */,
3DC0BC6922728FF1001145EC /* Info.plist */,
3DCAAA7C22ADE9830011A2DA /* checkUpdate.swift */,
Expand Down Expand Up @@ -312,6 +315,7 @@
3DD4B664226C1CF000451B7B /* lowlevel.c in Sources */,
3DCAAA7D22ADE9830011A2DA /* checkUpdate.swift in Sources */,
3D95379522784D550017D8B9 /* AboutBox.swift in Sources */,
3D6070E226DBC68E00EE4E48 /* LEDeviceInfo.swift in Sources */,
3D79FD7D226C335100A373C0 /* appleDeviceNames.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -354,7 +358,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = 42LGPQYC7M;
Expand Down Expand Up @@ -521,7 +525,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = BLEUnlock/BLEUnlock.entitlements;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = 42LGPQYC7M;
Expand Down
9 changes: 8 additions & 1 deletion BLEUnlock/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
var unlockedAt = 0.0
var inScreensaver = false
var lastRSSI: Int? = nil


override init() {
// Hide dock icon.
// This is required because we can't have LSUIElement set to true in Info.plist,
// otherwise CBCentralManager.scanForPeripherals won't work.
NSApp.setActivationPolicy(.accessory)
}

func menuWillOpen(_ menu: NSMenu) {
if menu == deviceMenu {
ble.startScanning()
Expand Down
18 changes: 16 additions & 2 deletions BLEUnlock/BLE.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ func getNameFromMAC(_ mac: String) -> String? {
guard let plist = NSDictionary(contentsOfFile: "/Library/Preferences/com.apple.Bluetooth.plist") else { return nil }
guard let devcache = plist["DeviceCache"] as? NSDictionary else { return nil }
guard let device = devcache[mac] as? NSDictionary else { return nil }
return device["Name"] as? String
if let name = device["Name"] as? String {
let trimmed = name.trimmingCharacters(in: .whitespaces)
if trimmed == "" { return nil }
return trimmed
}
return nil
}

class Device: NSObject {
Expand All @@ -34,12 +39,21 @@ class Device: NSObject {

override var description: String {
get {
if macAddr == nil || blName == nil {
if let info = getLEDeviceInfoFromUUID(uuid.description) {
blName = info.name
macAddr = info.macAddr
}
}
if macAddr == nil {
macAddr = getMACFromUUID(uuid.description)
}
if let mac = macAddr {
blName = getNameFromMAC(mac)
if blName == nil {
blName = getNameFromMAC(mac)
}
if let name = blName {
// If it's just "iPhone" or "iPad", there's a chance we can get the model name in the following code
if name != "iPhone" && name != "iPad" {
return name
}
Expand Down
4 changes: 1 addition & 3 deletions BLEUnlock/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@
<key>CFBundleShortVersionString</key>
<string>1.10.3</string>
<key>CFBundleVersion</key>
<string>741</string>
<string>764</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>BLEUnlock uses Bluetooth to detect devices.</string>
<key>NSHumanReadableCopyright</key>
Expand Down
90 changes: 90 additions & 0 deletions BLEUnlock/LEDeviceInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Resolve MAC address and device name of BLE device from SQLite database at /Library/Bluetooth introduced in Monterey.

import SQLite3

private var inited = false
private var db_paired: OpaquePointer?
private var db_other: OpaquePointer?

private func connect() {
if inited { return }

if sqlite3_open("/Library/Bluetooth/com.apple.MobileBluetooth.ledevices.paired.db", &db_paired) == SQLITE_OK {
print("paired.db open success")
} else {
db_paired = nil
}

if sqlite3_open("/Library/Bluetooth/com.apple.MobileBluetooth.ledevices.other.db", &db_other) == SQLITE_OK {
print("other.db open success")
} else {
db_other = nil
}

inited = true
}

struct LEDeviceInfo {
var name: String?
var macAddr: String?
}

private func getStringFromRow(stmt: OpaquePointer?, index: Int32) -> String? {
if sqlite3_column_type(stmt, index) != SQLITE_TEXT { return nil }
let s = String(cString: sqlite3_column_text(stmt, index))
let trimmed = s.trimmingCharacters(in: .whitespaces)
if trimmed == "" { return nil }
return trimmed
}

private func getPairedDeviceFromUUID(_ uuid: String) -> LEDeviceInfo? {
guard let db = db_paired else { return nil }
var stmt: OpaquePointer?
if sqlite3_prepare(db, "SELECT Name, Address, ResolvedAddress FROM PairedDevices where Uuid='\(uuid)'", -1, &stmt, nil) != SQLITE_OK {
print("failed to prepare")
return nil
}
if sqlite3_step(stmt) != SQLITE_ROW {
return nil
}
let name = getStringFromRow(stmt: stmt, index: 0)
let address = getStringFromRow(stmt: stmt, index: 1)
let resolvedAddress = getStringFromRow(stmt: stmt, index: 2)
var mac: String? = nil
if let addr = resolvedAddress ?? address {
// It's like "Public XX:XX:..." or "Random XX:XX:...", so split by space and take the second one
let parts = addr.split(separator: " ")
if parts.count > 1 {
mac = String(parts[1])
}
}
return LEDeviceInfo(name: name, macAddr: mac)
}

private func getOtherDeviceFromUUID(_ uuid: String) -> LEDeviceInfo? {
guard let db = db_other else { return nil }
var stmt: OpaquePointer?
if sqlite3_prepare(db, "SELECT Name, Address FROM OtherDevices where Uuid='\(uuid)'", -1, &stmt, nil) != SQLITE_OK {
print("failed to prepare")
return nil
}
if sqlite3_step(stmt) != SQLITE_ROW {
return nil
}
let name = getStringFromRow(stmt: stmt, index: 0)
let address = getStringFromRow(stmt: stmt, index: 1)
var mac: String? = nil
if let addr = address {
// It's like "Public XX:XX:..." or "Random XX:XX:...", so split by space and take the second one
let parts = addr.split(separator: " ")
if parts.count > 1 {
mac = String(parts[1])
}
}
return LEDeviceInfo(name: name, macAddr: mac)
}

func getLEDeviceInfoFromUUID(_ uuid: String) -> LEDeviceInfo? {
connect()
return getPairedDeviceFromUUID(uuid) ?? getOtherDeviceFromUUID(uuid);
}

0 comments on commit 3fef53d

Please sign in to comment.