Skip to content

Instantly share code, notes, and snippets.

@afedotov
Created February 3, 2023 02:01
Show Gist options
  • Save afedotov/e94a73735edd8b69d7661017e8a76ef7 to your computer and use it in GitHub Desktop.
Save afedotov/e94a73735edd8b69d7661017e8a76ef7 to your computer and use it in GitHub Desktop.
Proof-of-Concept: extract GAN smart cube MAC address using Web Bluetooth
/**
*
* 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