Created
February 3, 2023 02:01
-
-
Save afedotov/e94a73735edd8b69d7661017e8a76ef7 to your computer and use it in GitHub Desktop.
Proof-of-Concept: extract GAN smart cube MAC address using Web Bluetooth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* Proof-of-Concept: extract GAN smart cube MAC address using Web Bluetooth. | |
* MAC address resides at last 6 bytes in Manufacturer Specific Data field | |
* of the bluetooth advertising packet. | |
* | |
* In order for this to work it is necessary to enable following flag in Chrome: | |
* | |
* chrome://flags/#enable-web-bluetooth-new-permissions-backend | |
* | |
*/ | |
const BT_GAN_MANUFACTURER_ID: number = 0x0001; | |
const BT_GAN_SERVICES = ['6e400001-b5a3-f393-e0a9-e50e24dc4179']; | |
export interface GanConnection { | |
device?: BluetoothDevice; | |
server?: BluetoothRemoteGATTServer; | |
deviceName?: string; | |
deviceMAC?: string; | |
} | |
// Extract MAC from last 6 bytes of Manufacturer Specific Data | |
function extractMAC(manufacturerData: BluetoothManufacturerData): string { | |
var mac: Array<string> = []; | |
var dataView = manufacturerData.get(BT_GAN_MANUFACTURER_ID); | |
if (dataView && dataView.byteLength > 6) { | |
for (let i = 1; i <= 6; i++) { | |
mac.push(dataView.getUint8(dataView.byteLength - i).toString(16).padStart(2, '0')); | |
} | |
} | |
return mac.join(':'); | |
} | |
// Wait for single advertising packet from device | |
async function waitForAdvertismentFromDevice(bluetoothDevice: BluetoothDevice): Promise<BluetoothAdvertisingEvent> { | |
return new Promise<BluetoothAdvertisingEvent>((resolve) => { | |
var abortController = new AbortController(); | |
bluetoothDevice.addEventListener("advertisementreceived", (advertisingEvent) => { | |
abortController.abort(); | |
resolve(advertisingEvent); | |
}); | |
bluetoothDevice.watchAdvertisements({ signal: abortController.signal }); | |
}); | |
} | |
export async function connectToGANCube(): Promise<GanConnection> { | |
var conn: GanConnection = {}; | |
// Request user for the bluetooth device (popup selection dialog) | |
conn.device = await navigator.bluetooth.requestDevice( | |
{ | |
filters: [{ namePrefix: "GAN" }], | |
optionalServices: BT_GAN_SERVICES, | |
optionalManufacturerData: [BT_GAN_MANUFACTURER_ID] | |
} | |
); | |
// Wait for advertising packet from requested device | |
var advEvt = await waitForAdvertismentFromDevice(conn.device); | |
conn.deviceName = advEvt.name; | |
conn.deviceMAC = extractMAC(advEvt.manufacturerData); | |
// Connect to GATT server | |
conn.server = await conn.device.gatt?.connect(); | |
return conn; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment