diff --git a/README-cn.md b/README-cn.md index 719641e..72872c8 100644 --- a/README-cn.md +++ b/README-cn.md @@ -1,9 +1,5 @@ -

-Bluing -

-

-为 hack 蓝牙而生的情报收集工具 -

+

Bluing

+

为 hack 蓝牙而生的情报收集工具

English · 简体中文 @@ -55,7 +51,6 @@ Usage: bluing [-h | --help] bluing (-v | --version) bluing [-i <hci>] --clean BD_ADDR - bluing [-i <hci>] --spoof-bd-addr BD_ADDR bluing --flash-micro-bit bluing <command> [<args>...] @@ -67,29 +62,19 @@ Options: -v, --version Print version information and quit -i <hci> HCI device --clean Clean cached data of a remote device - --spoof-bd-addr Spoof the BD_ADDR of a local controller --flash-micro-bit Download the dedicated firmware to micro:bit(s) Commands: br Basic Rate system, includes an optional Enhanced Data Rate (EDR) extension le Low Energy system android Android Bluetooth stack + spoof Spoof with new local device information plugin Manage plugins Run `bluing <command> --help` for more information on a command. -### `--spoof-bd-addr`:本地控制器 BD_ADDR 伪装 - -

$ sudo bluing --spoof-bd-addr AA:BB:CC:DD:EE:FF - -
-[WARNING] The original HCI device number may have been changed
-[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
-
-
- ### `br` 命令:Basic Rate system
$ bluing br --help @@ -525,6 +510,67 @@ btsnoop_hci.log: BTSnoop version 1, HCI UART (H4)
+### `spoof` 命令:使用新的设备信息做欺骗 + +
$ bluing spoof --help + +
+Usage:
+    bluing spoof [-h | --help]
+    bluing spoof [-i <hci>] --bd-addr=<BD_ADDR>
+    bluing spoof [-i <hci>] --cls-of-dev=<num>
+    bluing spoof --host-name=<name>
+    bluing spoof [-i <hci>] --alias=<alias>
+
+Options:
+    -h, --help             Print this help and quit
+    -i <hci>               HCI device
+    --bd-addr=<BD_ADDR>    Spoof with a new BD_ADDR
+    --cls-of-dev=<num>     Spoof with a new Class of Device
+    --host-name=<name>     Spoof with a new host name
+    --alias=<alias>        Spoof with a new alias
+
+
+ +#### `--bd-addr=`:使用新的设备地址做欺骗 + +该功能当前基于 `spooftooph` 完成。如果在 Kali Linux 上使用它,先执行 `sudo apt install spooftooph` 即可完成安装。但在 Ubuntu 上使用时,则需要手动编译安装 [`spooftooph`](https://gitlab.com/kalilinux/packages/spooftooph)。 + +
$ sudo bluing spoof --bd-addr=AA:BB:CC:DD:EE:FF + +
+[WARNING] The original HCI device number may have been changed
+[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
+
+
+ +#### `--cls-of-dev=`:使用新的设备类型做欺骗 + +
$ sudo bluing spoof --cls-of-dev=0x6c0100 + +
+No output when successful
+
+
+ +#### `--host-name=`:使用新的主机名做欺骗 + +
$ sudo bluing spoof --host-name=Bluing + +
+No output when successful
+
+
+ +#### `--alias=`:使用新的控制器别名做欺骗 + +
$ sudo bluing spoof --alias='Bluing Alias' + +
+No output when successful
+
+
+ ### `plugin` 命令:插件管理
$ bluing plugin --help @@ -557,9 +603,9 @@ Commands: Bluing 在嗅探 advertising physical channel PDU 时 ([`le --sniff-adv`](https://fo-000.github.io/bluing/index-cn.html#--sniff-adv%E5%97%85%E6%8E%A2-advertising-physical-channel-pdu)),至少需要 1 块 [original micro:bit](https://microbit.org/get-started/user-guide/overview/#original-micro:bit),且推荐同时使用 3 块。这些 micro:bit 需要运行 bluing 提供的专用固件。将 micro:bit 接入 Linux 后,执行如下命令便可刷写预先构建好的固件: -```sh -bluing --flash-micro-bit -``` +
+bluing --flash-micro-bit
+
除了 original micro:bit,使用 nRF51822 的其他板子也可以被支持,比如 Adafruit Bluefruit LE Friend 和 BLE400 with Core51822,但可能需要修改串口引脚的对应关系。 diff --git a/README.md b/README.md index 5c7c616..0f07e91 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ -

-Bluing -

-

-An intelligence gathering tool for hacking Bluetooth -

+

Bluing

+

An intelligence gathering tool for hacking Bluetooth

English · 简体中文 @@ -25,7 +21,7 @@ Bluing (formerly [bluescan](https://pypi.org/project/bluescan/)) is a **Blu**eto ![](https://raw.githubusercontent.com/fO-000/bluing/master/assets/bluing-features-mermaid-mindmap.svg) -## Install +## Installation Bluing partially depend on [BlueZ](http://www.bluez.org/), the official Linux Bluetooth protocol stack. So it only supports running on Linux. The following command is used to install dependencies: @@ -55,7 +51,6 @@ Usage: bluing [-h | --help] bluing (-v | --version) bluing [-i <hci>] --clean BD_ADDR - bluing [-i <hci>] --spoof-bd-addr BD_ADDR bluing --flash-micro-bit bluing <command> [<args>...] @@ -67,29 +62,19 @@ Options: -v, --version Print version information and quit -i <hci> HCI device --clean Clean cached data of a remote device - --spoof-bd-addr Spoof the BD_ADDR of a local controller --flash-micro-bit Download the dedicated firmware to micro:bit(s) Commands: br Basic Rate system, includes an optional Enhanced Data Rate (EDR) extension le Low Energy system android Android Bluetooth stack + spoof Spoof with new local device information plugin Manage plugins Run `bluing <command> --help` for more information on a command.

-### `--spoof-bd-addr`: Spoof the BD_ADDR of a local controller - -
$ sudo bluing --spoof-bd-addr AA:BB:CC:DD:EE:FF - -
-[WARNING] The original HCI device number may have been changed
-[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
-
-
- ### `br` command: Basic Rate system
$ bluing br --help @@ -525,6 +510,67 @@ btsnoop_hci.log: BTSnoop version 1, HCI UART (H4)
+### `spoof` command: Spoof with new local device information + +
$ bluing spoof --help + +
+Usage:
+    bluing spoof [-h | --help]
+    bluing spoof [-i <hci>] --bd-addr=<BD_ADDR>
+    bluing spoof [-i <hci>] --cls-of-dev=<num>
+    bluing spoof --host-name=<name>
+    bluing spoof [-i <hci>] --alias=<alias>
+
+Options:
+    -h, --help             Print this help and quit
+    -i <hci>               HCI device
+    --bd-addr=<BD_ADDR>    Spoof with a new BD_ADDR
+    --cls-of-dev=<num>     Spoof with a new Class of Device
+    --host-name=<name>     Spoof with a new host name
+    --alias=<alias>        Spoof with a new alias
+
+
+ +#### Spoofing with a new BD_ADDR + +This feature is currently based on `spooftooph`, which can be installed by runing `sudo apt install spooftooph` if you are using it on Kali Linux. However, if you are using this feature on Ubuntu, you will need to manually compile and install [`spooftooph`](https://gitlab.com/kalilinux/packages/spooftooph). + +
$ sudo bluing spoof --bd-addr=AA:BB:CC:DD:EE:FF + +
+[WARNING] The original HCI device number may have been changed
+[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
+
+
+ +#### `--cls-of-dev=`: Spoof with a new Class of Device + +
$ sudo bluing spoof --cls-of-dev=0x6c0100 + +
+No output when successful
+
+
+ +#### `--host-name=`: Spoof with a new host name + +
$ sudo bluing spoof --host-name=Bluing + +
+No output when successful
+
+
+ +#### `--alias=`: Spoof with a new controller alias + +
$ sudo bluing spoof --alias='Bluing Alias' + +
+No output when successful
+
+
+ ### `plugin` command: Manage plugins
$ bluing plugin --help @@ -555,9 +601,9 @@ Many features of bluing require access to at least 1 Bluetooth adapter. Although Bluing requires at least 1 [original micro:bit](https://microbit.org/get-started/user-guide/overview/#original-micro:bit) when sniffing advertising physical channel PDUs ([`le --sniff-adv`](https://fo-000.github.io/bluing/#--sniff-adv-sniff-advertising-physical-channel-pdu)), and it is recommended to use 3 of them at the same time. These micro:bits need to run the dedicated firmware provided by bluing. After connecting the micro:bits to Linux, the pre-built firmware can be flashed by executing the following command: -```sh -bluing --flash-micro-bit -``` +
+bluing --flash-micro-bit
+
While less convenient to use than the micro:bit, but more accessible to purchase, more generic NRF51 adapters can be supported as well. Support has been added for the Adafruit Bluefruit LE Friend and the BLE400 boards. To use these, they will need to be flashed using SWD. This tool does not support flashing these devices. Additionally, the tool cannot automatically identify these devices. Instead the `--devices` option needs to identify the ports connected to computer. diff --git a/assets/bluing-features-mermaid-mindmap-cn.svg b/assets/bluing-features-mermaid-mindmap-cn.svg index 893dd22..77c645e 100644 --- a/assets/bluing-features-mermaid-mindmap-cn.svg +++ b/assets/bluing-features-mermaid-mindmap-cn.svg @@ -1 +1 @@ -Bluing本地适配器 BD_ADDR 伪装PluginBasic Rate system发现附近其他的 BR/EDR控制器检索远端 BD/EDR 设备的SDP 数据库信息嗅探并推测附近的 BD_ADDR读取远端 BR/EDR 设备的LMP 特性打印附近其他 BR/EDR设备进来的连接Android收集正在产生的 btsnoop logLow Energy system发现附近正在 advertising的设备读取远端 LE 设备的 LLFeatureSet请求远端 LE 设备的 pairingfeature发现远端 LE 设备 GATTProfile 的层次结构嗅探 advertising physicalchannel PDU \ No newline at end of file +BluingPlugin欺骗BD_ADDR设备类型主机名称适配器别名Basic Rate system发现附近其他的 BR/EDR控制器检索远端 BD/EDR 设备的SDP 数据库信息嗅探并推测附近的 BD_ADDR读取远端 BR/EDR 设备的LMP 特性打印附近其他 BR/EDR设备进来的连接Android收集正在产生的 btsnoop logLow Energy system发现附近正在 advertising的设备读取远端 LE 设备的 LLFeatureSet请求远端 LE 设备的 pairingfeature发现远端 LE 设备 GATTProfile 的层次结构嗅探 advertising physicalchannel PDU \ No newline at end of file diff --git a/assets/bluing-features-mermaid-mindmap.svg b/assets/bluing-features-mermaid-mindmap.svg index d0d37c0..7f59add 100644 --- a/assets/bluing-features-mermaid-mindmap.svg +++ b/assets/bluing-features-mermaid-mindmap.svg @@ -1 +1 @@ -BluingSpoof the BD_ADDR of alocal controllerPluginBasic Rate systemDiscover other nearbyBR/EDR controllersRetrieve information fromthe SDP database of aremote BR/EDR deviceRead LMP features of aremote BR/EDR deviceSniff and guess nearbyBD_ADDRsPrint incoming connectionfrom other nearby BR/EDRdevicesAndroidCollect the btsnoop logbeing generatedLow Energy systemDiscover advertisingdevices nearbyRead LL FeatureSet of aremote LE deviceRequest the pairing featureof a remote LE deviceDiscover GATT Profilehierarchy of a remote LEdeviceSniff advertising physicalchannel PDU \ No newline at end of file +BluingPluginSpoofHost nameController aliasClass of DeviceBD_ADDRBasic Rate systemDiscover other nearbyBR/EDR controllersRetrieve information fromthe SDP database of aremote BR/EDR deviceRead LMP features of aremote BR/EDR deviceSniff and guess nearbyBD_ADDRsPrint incoming connectionfrom other nearby BR/EDRdevicesAndroidCollect the btsnoop logbeing generatedLow Energy systemDiscover advertisingdevices nearbyRead LL FeatureSet of aremote LE deviceRequest the pairing featureof a remote LE deviceDiscover GATT Profilehierarchy of a remote LEdeviceSniff advertising physicalchannel PDU \ No newline at end of file diff --git a/index-cn.html b/index-cn.html index 18d9ec7..e4bcace 100644 --- a/index-cn.html +++ b/index-cn.html @@ -682,12 +682,8 @@
-

-Bluing -

-

-为 hack 蓝牙而生的情报收集工具 -

+

Bluing

+

为 hack 蓝牙而生的情报收集工具

English · 简体中文

@@ -725,7 +721,6 @@

安装

bluing [-h | --help] bluing (-v | --version) bluing [-i <hci>] --clean BD_ADDR - bluing [-i <hci>] --spoof-bd-addr BD_ADDR bluing --flash-micro-bit bluing <command> [<args>...] @@ -737,25 +732,18 @@

安装

-v, --version Print version information and quit -i <hci> HCI device --clean Clean cached data of a remote device - --spoof-bd-addr Spoof the BD_ADDR of a local controller --flash-micro-bit Download the dedicated firmware to micro:bit(s) Commands: br Basic Rate system, includes an optional Enhanced Data Rate (EDR) extension le Low Energy system android Android Bluetooth stack + spoof Spoof with new local device information plugin Manage plugins Run `bluing <command> --help` for more information on a command.
-

--spoof-bd-addr:本地控制器 BD_ADDR 伪装

- -
$ sudo bluing --spoof-bd-addr AA:BB:CC:DD:EE:FF -
[WARNING] The original HCI device number may have been changed
-[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
-
-

br 命令:Basic Rate system

$ bluing br --help @@ -1149,6 +1137,51 @@

spoof 命令:使用新的设备信息做欺骗

+ +
$ bluing spoof --help +
Usage:
+    bluing spoof [-h | --help]
+    bluing spoof [-i <hci>] --bd-addr=<BD_ADDR>
+    bluing spoof [-i <hci>] --cls-of-dev=<num>
+    bluing spoof --host-name=<name>
+    bluing spoof [-i <hci>] --alias=<alias>
+
+Options:
+    -h, --help             Print this help and quit
+    -i <hci>               HCI device
+    --bd-addr=<BD_ADDR>    Spoof with a new BD_ADDR
+    --cls-of-dev=<num>     Spoof with a new Class of Device
+    --host-name=<name>     Spoof with a new host name
+    --alias=<alias>        Spoof with a new alias
+
+
+

--bd-addr=<BD_ADDR>:使用新的设备地址做欺骗

+ +

该功能当前基于 spooftooph 完成。如果在 Kali Linux 上使用它,先执行 sudo apt install spooftooph 即可完成安装。但在 Ubuntu 上使用时,则需要手动编译安装 spooftooph

+
$ sudo bluing spoof --bd-addr=AA:BB:CC:DD:EE:FF +
[WARNING] The original HCI device number may have been changed
+[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
+
+
+

--cls-of-dev=<num>:使用新的设备类型做欺骗

+ +
$ sudo bluing spoof --cls-of-dev=0x6c0100 +
No output when successful
+
+
+

--host-name=<name>:使用新的主机名做欺骗

+ +
$ sudo bluing spoof --host-name=Bluing +
No output when successful
+
+
+

--alias=<alias>:使用新的控制器别名做欺骗

+ +
$ sudo bluing spoof --alias='Bluing Alias' +
No output when successful
+
+

plugin 命令:插件管理

$ bluing plugin --help @@ -1176,8 +1209,9 @@



Original micro:bit(可选)

Bluing 在嗅探 advertising physical channel PDU 时 (le --sniff-adv),至少需要 1 块 original micro:bit,且推荐同时使用 3 块。这些 micro:bit 需要运行 bluing 提供的专用固件。将 micro:bit 接入 Linux 后,执行如下命令便可刷写预先构建好的固件:

-
bluing --flash-micro-bit
-

除了 original micro:bit,使用 nRF51822 的其他板子也可以被支持,比如 Adafruit Bluefruit LE Friend 和 BLE400 with Core51822,但可能需要修改串口引脚的对应关系。

+
bluing --flash-micro-bit
+
+

除了 original micro:bit,使用 nRF51822 的其他板子也可以被支持,比如 Adafruit Bluefruit LE Friend 和 BLE400 with Core51822,但可能需要修改串口引脚的对应关系。

Ubertooth One(可选)

当嗅探并推测附近的 BD_ADDR 时 (br --sniff-and-guess-bd-addr),bluing 需要用到一块 Ubertooth One

@@ -1224,11 +1258,7 @@

- -

--spoof-bd-addr:本地控制器 BD_ADDR 伪装

- -
+

br 命令:Basic Rate system

@@ -1296,6 +1326,31 @@

--collect-btsnoop-log: 收集正在产生的 btsnoop log

+ + +

+
+ +

spoof 命令:使用新的设备信息做欺骗

+
+
+
diff --git a/index.html b/index.html index f174e1c..1610c2e 100644 --- a/index.html +++ b/index.html @@ -682,12 +682,8 @@
-

-Bluing -

-

-An intelligence gathering tool for hacking Bluetooth -

+

Bluing

+

An intelligence gathering tool for hacking Bluetooth

English · 简体中文

@@ -702,7 +698,7 @@

Bluing (formerly bluescan) is a Bluetooth Intelligence Gathering tool written primarily in Python. It can help us snoop on the internal structure of Bluetooth which is a complex protocol, or hack Bluetooth devices. Here are the main features of the tool:

-

Install

+

Installation

Bluing partially depend on BlueZ, the official Linux Bluetooth protocol stack. So it only supports running on Linux. The following command is used to install dependencies:

sudo apt install python3-pip python3-dev libcairo2-dev libgirepository1.0-dev \
@@ -725,7 +721,6 @@ 

Install

bluing [-h | --help] bluing (-v | --version) bluing [-i <hci>] --clean BD_ADDR - bluing [-i <hci>] --spoof-bd-addr BD_ADDR bluing --flash-micro-bit bluing <command> [<args>...] @@ -737,25 +732,18 @@

Install

-v, --version Print version information and quit -i <hci> HCI device --clean Clean cached data of a remote device - --spoof-bd-addr Spoof the BD_ADDR of a local controller --flash-micro-bit Download the dedicated firmware to micro:bit(s) Commands: br Basic Rate system, includes an optional Enhanced Data Rate (EDR) extension le Low Energy system android Android Bluetooth stack + spoof Spoof with new local device information plugin Manage plugins Run `bluing <command> --help` for more information on a command.
-

--spoof-bd-addr: Spoof the BD_ADDR of a local controller

- -
$ sudo bluing --spoof-bd-addr AA:BB:CC:DD:EE:FF -
[WARNING] The original HCI device number may have been changed
-[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
-
-

br command: Basic Rate system

$ bluing br --help @@ -1149,6 +1137,51 @@

spoof command: Spoof with new local device information

+ +
$ bluing spoof --help +
Usage:
+    bluing spoof [-h | --help]
+    bluing spoof [-i <hci>] --bd-addr=<BD_ADDR>
+    bluing spoof [-i <hci>] --cls-of-dev=<num>
+    bluing spoof --host-name=<name>
+    bluing spoof [-i <hci>] --alias=<alias>
+
+Options:
+    -h, --help             Print this help and quit
+    -i <hci>               HCI device
+    --bd-addr=<BD_ADDR>    Spoof with a new BD_ADDR
+    --cls-of-dev=<num>     Spoof with a new Class of Device
+    --host-name=<name>     Spoof with a new host name
+    --alias=<alias>        Spoof with a new alias
+
+
+

Spoofing with a new BD_ADDR

+ +

This feature is currently based on spooftooph, which can be installed by runing sudo apt install spooftooph if you are using it on Kali Linux. However, if you are using this feature on Ubuntu, you will need to manually compile and install spooftooph.

+
$ sudo bluing spoof --bd-addr=AA:BB:CC:DD:EE:FF +
[WARNING] The original HCI device number may have been changed
+[INFO] BD_ADDR changed: 11:22:33:44:55:66 -> AA:BB:CC:DD:EE:FF
+
+
+

--cls-of-dev=<num>: Spoof with a new Class of Device

+ +
$ sudo bluing spoof --cls-of-dev=0x6c0100 +
No output when successful
+
+
+

--host-name=<name>: Spoof with a new host name

+ +
$ sudo bluing spoof --host-name=Bluing +
No output when successful
+
+
+

--alias=<alias>: Spoof with a new controller alias

+ +
$ sudo bluing spoof --alias='Bluing Alias' +
No output when successful
+
+

plugin command: Manage plugins

$ bluing plugin --help @@ -1174,8 +1207,9 @@

Bluetooth adapter

Original micro:bit (optional)

Bluing requires at least 1 original micro:bit when sniffing advertising physical channel PDUs (le --sniff-adv), and it is recommended to use 3 of them at the same time. These micro:bits need to run the dedicated firmware provided by bluing. After connecting the micro:bits to Linux, the pre-built firmware can be flashed by executing the following command:

-
bluing --flash-micro-bit
-

While less convenient to use than the micro:bit, but more accessible to purchase, more generic NRF51 adapters can be supported as well. Support has been added for the Adafruit Bluefruit LE Friend and the BLE400 boards. To use these, they will need to be flashed using SWD. This tool does not support flashing these devices. Additionally, the tool cannot automatically identify these devices. Instead the --devices option needs to identify the ports connected to computer.

+
bluing --flash-micro-bit
+
+

While less convenient to use than the micro:bit, but more accessible to purchase, more generic NRF51 adapters can be supported as well. Support has been added for the Adafruit Bluefruit LE Friend and the BLE400 boards. To use these, they will need to be flashed using SWD. This tool does not support flashing these devices. Additionally, the tool cannot automatically identify these devices. Instead the --devices option needs to identify the ports connected to computer.

Ubertooth One (optional)

When sniffing and guessing nearby BD_ADDRs (br --sniff-and-guess-bd-addr), bluing requires an Ubertooth One.

@@ -1213,8 +1247,8 @@

Manag

+
+ +

spoof command: Spoof with new local device information

+
+
+
diff --git a/setup.cfg b/setup.cfg index 1363efb..cf21ce9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -35,8 +35,8 @@ install_requires = pyserial >= 3.5 PyGObject >= 3.42.2 dbus-python >= 1.3.2 - xpycommon >= 0.0.23 - bthci >= 0.0.41 + xpycommon >= 0.0.25 + bthci >= 0.0.44 btsm >= 0.0.16 btatt >= 0.0.19 btgatt >= 0.0.22 @@ -45,10 +45,11 @@ package_dir = =src packages = bluing - bluing.android bluing.br bluing.le bluing.le.res + bluing.android + bluing.spoof bluing.plugin bluing.plugin.list bluing.plugin.install diff --git a/src/bluing/__init__.py b/src/bluing/__init__.py index 72425ae..25178d6 100644 --- a/src/bluing/__init__.py +++ b/src/bluing/__init__.py @@ -2,7 +2,7 @@ PKG_NAME = 'bluing' APP_NAME = PKG_NAME -VERSION = '0.11.1' +VERSION = '0.12.0' DEBUG_VERSION = '' diff --git a/src/bluing/__main__.py b/src/bluing/__main__.py index bcec6c5..9a51f6f 100644 --- a/src/bluing/__main__.py +++ b/src/bluing/__main__.py @@ -8,7 +8,8 @@ from xpycommon.log import Logger from xpycommon.ui import red, blue -from xpycommon.bluetooth import spoof_bd_addr +from xpycommon.bluetooth.bluez import stop_bluetooth_service, \ + restart_bluetooth_service from bthci import HCI @@ -16,16 +17,18 @@ from .ui import parse_cmdline from .br import main as br_main from .le import main as le_main -from .plugin import main as plugin_main from .android import main as android_main +from .spoof import main as spoof_main +from .plugin import main as plugin_main logger = Logger(__name__, LOG_LEVEL) cmd_to_main = { 'br': br_main, 'le': le_main, + 'android': android_main, + 'spoof': spoof_main, 'plugin': plugin_main, - 'android': android_main } @@ -36,9 +39,7 @@ def clean(iface: str, raddr: str): raddr = raddr.upper() - output = check_output( - ' '.join(['sudo', 'systemctl', 'stop', 'bluetooth.service']), - stderr=STDOUT, timeout=60, shell=True) + stop_bluetooth_service() output = check_output( ' '.join(['sudo', 'rm', '-rf', '/var/lib/bluetooth/' + \ @@ -54,9 +55,7 @@ def clean(iface: str, raddr: str): if output != b'': logger.info(output.decode()) - output = check_output( - ' '.join(['sudo', 'systemctl', 'start', 'bluetooth.service']), - stderr=STDOUT, timeout=60, shell=True) + restart_bluetooth_service() def flash_micro_bit(): @@ -91,9 +90,11 @@ def main(argv: list[str] = sys.argv): try: if args[''] is None: if args['--clean']: + # TODO + # * When there is no HCI device in the system, clean + # cahces based on the BD_ADDR provided by users. + # * Prompt the user when the directory does not exist. clean(args['-i'], args['BD_ADDR']) - elif args['--spoof-bd-addr']: - spoof_bd_addr(args['BD_ADDR'], args['-i']) elif args['--flash-micro-bit']: flash_micro_bit() else: diff --git a/src/bluing/android/__main__.py b/src/bluing/android/__main__.py index ffc48e6..2a44be1 100644 --- a/src/bluing/android/__main__.py +++ b/src/bluing/android/__main__.py @@ -21,7 +21,7 @@ def main(argv: list[str] = sys.argv): " args: {}".format(args)) try: - if args['--collect-btsnoop-log']: + if args['--collect-btsnoop-log']: # Only can run once during a Bluetooth session. transport_ids = get_adb_transport_ids() if args['-t'] is None: if len(transport_ids) == 0: diff --git a/src/bluing/android/ui.py b/src/bluing/android/ui.py index 9af6069..c914825 100644 --- a/src/bluing/android/ui.py +++ b/src/bluing/android/ui.py @@ -19,7 +19,8 @@ from docopt import docopt from xpycommon.log import Logger -from xpycommon import str2int, check_malicious_char +from xpycommon.cmdline_arg_converter import CmdlineArgConverter +from xpycommon import check_malicious_char from xpycommon.ui import red from xpycommon.android import get_adb_transport_ids @@ -46,7 +47,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: if args['-t'] is not None: try: - args['-t'] = str2int(args['-t']) + args['-t'] = CmdlineArgConverter.str2int(args['-t']) except ValueError as e: e.args = ("Invalid -t: " + red(args['-t']),) raise e diff --git a/src/bluing/br/__init__.py b/src/bluing/br/__init__.py index 75d981c..2eec900 100644 --- a/src/bluing/br/__init__.py +++ b/src/bluing/br/__init__.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -PKG_NAME = 'br' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL + +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'br']) LOG_LEVEL = PARENT_LOG_LEVEL # LOG_LEVEL = DEBUG diff --git a/src/bluing/br/__main__.py b/src/bluing/br/__main__.py index 8504f4d..2fcb4a5 100644 --- a/src/bluing/br/__main__.py +++ b/src/bluing/br/__main__.py @@ -93,7 +93,7 @@ def main(argv: list[str] = sys.argv): " CoD: 0x{:06x}".format(blue(conn_req.bd_addr), conn_req.class_of_dev)) conn_req.class_of_dev.print_human_readable(2) - print(" link type: 0x{:02x} - {}".format(conn_req.link_type, conn_req.link_type.name)) + print(" Link type: 0x{:02x} - {}".format(conn_req.link_type, conn_req.link_type.name)) print() except KeyboardInterrupt: sys.exit() diff --git a/src/bluing/br/ui.py b/src/bluing/br/ui.py index 5f38c9e..cd63f7f 100644 --- a/src/bluing/br/ui.py +++ b/src/bluing/br/ui.py @@ -50,12 +50,12 @@ from docopt import docopt from bthci import HCI +from bthci.commands import HCI_Inquiry from xpycommon.log import Logger -from xpycommon.ui import red -from xpycommon.bluetooth import verify_bd_addr +from xpycommon.ui import red, blue +from xpycommon.bluetooth import BD_ADDR -from .. import PKG_NAME as BLUING_PKG_NAME from . import LOG_LEVEL, PKG_NAME @@ -64,10 +64,10 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: logger.debug("Entered parse_cmdline(argv={})".format(argv)) - + # In order to use `options_first=True` for strict compatibility with POSIX. # This replaces multi-level commands in `__doc__` with single-level commands. - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PKG_NAME]), PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) @@ -101,6 +101,11 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: e.args = ("Invalid --inquiry-len: " + red(args['--inquiry-len']),) raise e + if args['--inquiry-len'] < HCI_Inquiry.MIN_INQUIRY_LEN or args['--inquiry-len'] > HCI_Inquiry.MAX_INQUIRY_LEN: + raise ValueError("`--inquiry-len={}` is not between {} and {}".format( + red(str(args['--inquiry-len'])), blue(str(HCI_Inquiry.MIN_INQUIRY_LEN)), + blue(str(HCI_Inquiry.MAX_INQUIRY_LEN)))) + try: args['--timeout'] = int(args['--timeout']) except ValueError: @@ -111,7 +116,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: raise e if args['BD_ADDR']: - if not verify_bd_addr(args['BD_ADDR']): + if not BD_ADDR.verify(args['BD_ADDR']): raise ValueError("Invalid BD_ADDR: " + red(args['BD_ADDR'])) args['BD_ADDR'] = args['BD_ADDR'].upper() diff --git a/src/bluing/le/__init__.py b/src/bluing/le/__init__.py index bad9e06..e351b58 100644 --- a/src/bluing/le/__init__.py +++ b/src/bluing/le/__init__.py @@ -1,21 +1,17 @@ #!/usr/bin/env python -PKG_NAME = 'le' - - from pathlib import Path -PKG_ROOT = Path(__file__).parent -LE_DEVS_SCAN_RESULT_CACHE = PKG_ROOT/'res'/'le_devs_scan_result.cache' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'le']) +PKG_ROOT = Path(__file__).parent LOG_LEVEL = PARENT_LOG_LEVEL # LOG_LEVEL = DEBUG +LE_DEVS_SCAN_RESULT_CACHE = PKG_ROOT/'res'/'le_devs_scan_result.cache' from .__main__ import main diff --git a/src/bluing/le/ui.py b/src/bluing/le/ui.py index 28c4c2a..315c9ba 100644 --- a/src/bluing/le/ui.py +++ b/src/bluing/le/ui.py @@ -42,12 +42,10 @@ from xpycommon.log import Logger from xpycommon.ui import blue, yellow, red -from xpycommon.bluetooth import verify_bd_addr +from xpycommon.bluetooth import BD_ADDR from docopt import docopt from bthci import ADDR_TYPE_PUBLIC, ADDR_TYPE_RANDOM, HCI -from .. import PKG_NAME as BLUING_PKG_NAME - from . import LOG_LEVEL, PKG_NAME from .le_scan import LeScanner @@ -58,7 +56,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: logger.debug("Entered parse_cmdline(argv={})".format(argv)) - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PKG_NAME]), PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) @@ -107,7 +105,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: raise ValueError("Invalid --io-cap: " + red(args['--io-cap'])) if args['PEER_ADDR'] is not None: - if not verify_bd_addr(args['PEER_ADDR']): + if not BD_ADDR.verify(args['PEER_ADDR']): raise ValueError("Invalid PEER_ADDR: " + red(args['BD_ADDR'])) args['PEER_ADDR'] = args['PEER_ADDR'].upper() diff --git a/src/bluing/plugin/__init__.py b/src/bluing/plugin/__init__.py index f303e4e..82f7f81 100644 --- a/src/bluing/plugin/__init__.py +++ b/src/bluing/plugin/__init__.py @@ -1,64 +1,16 @@ #!/usr/bin/env python -PKG_NAME = 'plugin' - -from xpycommon.plugin import Plugin, PluginManager, PluginError, PluginInstallError, PluginUninstallError, \ - PluginOptionError, PluginRuntimeError, PluginPrepareError, \ - PluginRunError, PluginCleanError from xpycommon.log import INFO, DEBUG -from .. import PKG_NAME as BLUING_PKG_NAME, LOG_LEVEL as BLUING_LOG_LEVEL - - -LOG_LEVEL = BLUING_LOG_LEVEL - - -class BluingPluginError(PluginError): - """""" - - -class BluingPluginInstallError(BluingPluginError, PluginInstallError): - """""" - - -class BluingPluginUninstallError(BluingPluginError, PluginUninstallError): - """""" - - -class BluingPluginOptionError(BluingPluginError, PluginOptionError): - """""" - - -class BluingPluginRuntimeError(BluingPluginError, PluginRuntimeError): - """""" - - -class BluingPluginPrepareError(BluingPluginError, PluginPrepareError): - """""" - - -class BluingPluginRunError(BluingPluginError, PluginRunError): - """""" - - -class BluingPluginCleanError(BluingPluginError, PluginCleanError): - """""" - - -class BluingPluginNotFoundError(BluingPluginError): - """run_plugin() may raise this exception""" - - -class BluingPlugin(Plugin): - """""" +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL -class BluingPluginManager(PluginManager): - MAGIC_CLASSIFIER = 'Framework :: BluInG :: Plugin' - ROOT = '/opt/{}-plugins'.format(BLUING_PKG_NAME) +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'plugin']) +LOG_LEVEL = PARENT_LOG_LEVEL +from .plugin import BluingPluginManager from .__main__ import main -__all__ = ['main'] +__all__ = ['main', 'BluingPluginManager'] diff --git a/src/bluing/plugin/exception.py b/src/bluing/plugin/exception.py new file mode 100644 index 0000000..00291ef --- /dev/null +++ b/src/bluing/plugin/exception.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +from xpycommon.plugin import PluginError, PluginInstallError, PluginUninstallError, \ + PluginOptionError, PluginRuntimeError, PluginPrepareError, \ + PluginRunError, PluginCleanError + + +class BluingPluginError(PluginError): + """""" + + +class BluingPluginInstallError(BluingPluginError, PluginInstallError): + """""" + + +class BluingPluginUninstallError(BluingPluginError, PluginUninstallError): + """""" + + +class BluingPluginOptionError(BluingPluginError, PluginOptionError): + """""" + + +class BluingPluginRuntimeError(BluingPluginError, PluginRuntimeError): + """""" + + +class BluingPluginPrepareError(BluingPluginError, PluginPrepareError): + """""" + + +class BluingPluginRunError(BluingPluginError, PluginRunError): + """""" + + +class BluingPluginCleanError(BluingPluginError, PluginCleanError): + """""" + + +class BluingPluginNotFoundError(BluingPluginError): + """run_plugin() may raise this exception""" diff --git a/src/bluing/plugin/install/__init__.py b/src/bluing/plugin/install/__init__.py index c4f777f..8115e52 100644 --- a/src/bluing/plugin/install/__init__.py +++ b/src/bluing/plugin/install/__init__.py @@ -1,14 +1,11 @@ #!/usr/bin/env python - -PKG_NAME = 'install' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'install']) LOG_LEVEL = PARENT_LOG_LEVEL diff --git a/src/bluing/plugin/install/ui.py b/src/bluing/plugin/install/ui.py index 3a1a2bf..dcf3e59 100644 --- a/src/bluing/plugin/install/ui.py +++ b/src/bluing/plugin/install/ui.py @@ -18,7 +18,7 @@ from docopt import docopt from xpycommon.log import Logger -from .. import BLUING_PKG_NAME, PKG_NAME as PLUGIN_PKG_NAME, BluingPluginManager +from .. import BluingPluginManager from . import LOG_LEVEL, PKG_NAME @@ -30,8 +30,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: # In order to use `options_first=True` for strict compatibility with POSIX. # This replaces multi-level commands in `__doc__` with single-level commands. - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PLUGIN_PKG_NAME, PKG_NAME]), - PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) diff --git a/src/bluing/plugin/list/__init__.py b/src/bluing/plugin/list/__init__.py index c9c02bf..18feb94 100644 --- a/src/bluing/plugin/list/__init__.py +++ b/src/bluing/plugin/list/__init__.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -PKG_NAME = 'list' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL + +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'list']) LOG_LEVEL = PARENT_LOG_LEVEL diff --git a/src/bluing/plugin/list/ui.py b/src/bluing/plugin/list/ui.py index f9ccbed..17af325 100644 --- a/src/bluing/plugin/list/ui.py +++ b/src/bluing/plugin/list/ui.py @@ -15,8 +15,7 @@ from docopt import docopt from xpycommon.log import Logger -from .. import BLUING_PKG_NAME, PKG_NAME as PLUGIN_PKG_NAME -from . import LOG_LEVEL,PKG_NAME +from . import LOG_LEVEL, PKG_NAME logger = Logger(__name__, LOG_LEVEL) @@ -27,8 +26,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: # In order to use `options_first=True` for strict compatibility with POSIX. # This replaces multi-level commands in `__doc__` with single-level commands. - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PLUGIN_PKG_NAME, PKG_NAME]), - PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) diff --git a/src/bluing/plugin/plugin.py b/src/bluing/plugin/plugin.py new file mode 100644 index 0000000..81b314c --- /dev/null +++ b/src/bluing/plugin/plugin.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +from xpycommon.plugin import Plugin, PluginManager + +from . import PARENT_PKG_NAME + + +class BluingPlugin(Plugin): + """""" + + +class BluingPluginManager(PluginManager): + MAGIC_CLASSIFIER = 'Framework :: BluInG :: Plugin' + ROOT = '/opt/{}-plugins'.format(PARENT_PKG_NAME) diff --git a/src/bluing/plugin/run/__init__.py b/src/bluing/plugin/run/__init__.py index 9e39b32..58d24be 100644 --- a/src/bluing/plugin/run/__init__.py +++ b/src/bluing/plugin/run/__init__.py @@ -1,12 +1,11 @@ #!/usr/bin/env python -PKG_NAME = 'run' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARNET_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL + +PKG_NAME = '.'.join([PARNET_PKG_NAME, 'run']) LOG_LEVEL = PARENT_LOG_LEVEL # LOG_LEVEL = DEBUG diff --git a/src/bluing/plugin/run/ui.py b/src/bluing/plugin/run/ui.py index db3ca53..3cbd2a3 100644 --- a/src/bluing/plugin/run/ui.py +++ b/src/bluing/plugin/run/ui.py @@ -18,7 +18,6 @@ from docopt import docopt from xpycommon.log import Logger -from .. import BLUING_PKG_NAME, PKG_NAME as PLUGIN_PKG_NAME from . import LOG_LEVEL, PKG_NAME @@ -30,8 +29,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: # In order to use `options_first=True` for strict compatibility with POSIX. # This replaces multi-level commands in `__doc__` with single-level commands. - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PLUGIN_PKG_NAME, PKG_NAME]), - PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) diff --git a/src/bluing/plugin/ui.py b/src/bluing/plugin/ui.py index d0d27f6..263b1c9 100644 --- a/src/bluing/plugin/ui.py +++ b/src/bluing/plugin/ui.py @@ -21,8 +21,6 @@ from docopt import docopt from xpycommon.log import Logger -from .. import PKG_NAME as BLUING_PKG_NAME - from . import LOG_LEVEL, PKG_NAME @@ -32,7 +30,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: logger.debug("Entered parse_cmdline(argv={})".format(argv)) - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PKG_NAME]), PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) diff --git a/src/bluing/plugin/uninstall/__init__.py b/src/bluing/plugin/uninstall/__init__.py index 8dac65f..5c346c0 100644 --- a/src/bluing/plugin/uninstall/__init__.py +++ b/src/bluing/plugin/uninstall/__init__.py @@ -1,13 +1,11 @@ #!/usr/bin/env python -PKG_NAME = 'uninstall' - - from xpycommon.log import INFO, DEBUG -from .. import LOG_LEVEL as PARENT_LOG_LEVEL +from .. import PKG_NAME as PARNET_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL +PKG_NAME = '.'.join([PARNET_PKG_NAME, 'uninstall']) LOG_LEVEL = PARENT_LOG_LEVEL diff --git a/src/bluing/plugin/uninstall/ui.py b/src/bluing/plugin/uninstall/ui.py index 5838d09..23b2a60 100644 --- a/src/bluing/plugin/uninstall/ui.py +++ b/src/bluing/plugin/uninstall/ui.py @@ -18,7 +18,6 @@ from docopt import docopt from xpycommon.log import Logger -from .. import BLUING_PKG_NAME, PKG_NAME as PLUGIN_PKG_NAME, BluingPluginManager from . import LOG_LEVEL, PKG_NAME @@ -30,8 +29,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: # In order to use `options_first=True` for strict compatibility with POSIX. # This replaces multi-level commands in `__doc__` with single-level commands. - args = docopt(__doc__.replace(' '.join([BLUING_PKG_NAME, PLUGIN_PKG_NAME, PKG_NAME]), - PKG_NAME), + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), argv, help=False, options_first=True) logger.debug("docopt() returned\n" " args:", args) diff --git a/src/bluing/spoof/__init__.py b/src/bluing/spoof/__init__.py new file mode 100644 index 0000000..262638f --- /dev/null +++ b/src/bluing/spoof/__init__.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +from xpycommon.log import INFO, DEBUG + +from .. import PKG_NAME as PARENT_PKG_NAME, LOG_LEVEL as PARENT_LOG_LEVEL + + +PKG_NAME = '.'.join([PARENT_PKG_NAME, 'spoof']) +LOG_LEVEL = PARENT_LOG_LEVEL +# LOG_LEVEL = DEBUG + + +from .__main__ import main + +__all__ = ['main'] diff --git a/src/bluing/spoof/__main__.py b/src/bluing/spoof/__main__.py new file mode 100644 index 0000000..c4b8a49 --- /dev/null +++ b/src/bluing/spoof/__main__.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +import sys + +from xpycommon.log import Logger +from xpycommon.bluetooth.bluez import spoof_bd_addr, spoof_cls_of_dev, \ + spoof_host_name, spoof_controller_alias + +from . import LOG_LEVEL +from .ui import parse_cmdline + + +logger = Logger(__name__, LOG_LEVEL) + + +def main(argv: list[str] = sys.argv): + args = parse_cmdline(argv[1:]) + logger.debug("parse_cmdline() returned\n" + " args:", args) + + try: + if args['--bd-addr']: + spoof_bd_addr(args['--bd-addr'], args['-i']) + elif args['--cls-of-dev']: + spoof_cls_of_dev(args['--cls-of-dev'], args['-i']) + elif args['--host-name']: + spoof_host_name(args['--host-name']) + elif args['--alias']: + spoof_controller_alias(args['--alias'], args['-i']) + else: + raise ValueError("Invalid option(s)") + except Exception as e: + logger.error("{}: \"{}\"".format(e.__class__.__name__, e)) + sys.exit(1) diff --git a/src/bluing/spoof/ui.py b/src/bluing/spoof/ui.py new file mode 100644 index 0000000..232031f --- /dev/null +++ b/src/bluing/spoof/ui.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python + +r""" +Usage: + bluing spoof [-h | --help] + bluing spoof [-i ] --bd-addr= + bluing spoof [-i ] --cls-of-dev= + bluing spoof --host-name= + bluing spoof [-i ] --alias= + +Options: + -h, --help Print this help and quit + -i HCI device + --bd-addr= Spoof with a new BD_ADDR + --cls-of-dev= Spoof with a new Class of Device + --host-name= Spoof with a new host name + --alias= Spoof with a new alias +""" + + +import sys +from collections import Counter + +from docopt import docopt + +from xpycommon.cmdline_arg_converter import CmdlineArgConverter +from xpycommon.log import Logger +from xpycommon.ui import red +from xpycommon.bluetooth import BD_ADDR, ClassOfDevice, \ + verify_host_name, verify_controller_alias + +from bthci import HCI + +from . import PKG_NAME, LOG_LEVEL + +logger = Logger(__name__, LOG_LEVEL) + + +def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: + logger.debug("Entered parse_cmdline(argv={})".format(argv)) + + args = docopt(__doc__.replace(PKG_NAME.replace('.', ' '), PKG_NAME.split('.')[-1]), + argv, help=False, options_first=True) + logger.debug("docopt() returned\n" + " args:", args) + + try: + if args['--help'] or len(argv) == 0: + print(__doc__) + sys.exit() + + # Not all scenarios require HCI devcies. So when the HCI device is `None` + # (`-i` is `None`), in order to determine whether to use the default HCI + # device (need call `clean_up_running()`) or not need the HCI device at all, + # we can use other options to assist the determination. + hci_demanders = [args['--bd-addr'], args['--cls-of-dev'], args['--alias']] + hci_demander_counter = Counter(hci_demanders) + if hci_demander_counter[None] != len(hci_demanders): + if args['-i'] is None: + args['-i'] = HCI.get_default_iface() + + hci = HCI(args['-i']) + hci.clean_up_running() + hci.close() + + if args['--bd-addr']: + if not BD_ADDR.verify(args['--bd-addr']): + raise ValueError("Invalid BD_ADDR: " + red(args['BD_ADDR'])) + args['--bd-addr'] = args['--bd-addr'].upper() + + if args['--cls-of-dev']: + args['--cls-of-dev'] = CmdlineArgConverter.str2int(args['--cls-of-dev']) + if not ClassOfDevice.verify(args['--cls-of-dev']): + raise ValueError("Invalid Class of Device: " + red(args['--cls-of-dev'])) + + if args['--host-name']: + if not verify_host_name(args['--host-name']): + raise ValueError("Invalid host name: " + red(args['--host-name'])) + + if args['--alias']: + if not verify_controller_alias(args['--alias']): + raise ValueError("Invalid device name: " + red(args['--cls-of-dev'])) + + except Exception as e: + logger.error("{}: \"{}\"".format(e.__class__.__name__, e)) + sys.exit(1) + else: + return args diff --git a/src/bluing/ui.py b/src/bluing/ui.py index a6d9e44..e97384d 100644 --- a/src/bluing/ui.py +++ b/src/bluing/ui.py @@ -7,7 +7,6 @@ bluing [-h | --help] bluing (-v | --version) bluing [-i ] --clean BD_ADDR - bluing [-i ] --spoof-bd-addr BD_ADDR bluing --flash-micro-bit bluing [...] @@ -19,13 +18,13 @@ -v, --version Print version information and quit -i HCI device --clean Clean cached data of a remote device - --spoof-bd-addr Spoof the BD_ADDR of a local controller --flash-micro-bit Download the dedicated firmware to micro:bit(s) Commands: br Basic Rate system, includes an optional Enhanced Data Rate (EDR) extension le Low Energy system android Android Bluetooth stack + spoof Spoof with new local device information plugin Manage plugins Run `bluing --help` for more information on a command. @@ -38,7 +37,7 @@ from docopt import docopt from xpycommon.log import Logger from xpycommon.ui import red -from xpycommon.bluetooth import verify_bd_addr +from xpycommon.bluetooth import BD_ADDR from bthci import HCI from . import VERSION_STR, LOG_LEVEL @@ -50,12 +49,12 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: logger.debug("Entered parse_cmdline(argv={})".format(argv)) - args = docopt(__doc__, argv, version=VERSION_STR, options_first=True) + args = docopt(__doc__, argv, help=False, version=VERSION_STR, options_first=True) logger.debug("docopt() returned\n" " args:", args) try: - if len(argv) == 0: + if args['--help'] or len(argv) == 0: print(__doc__) sys.exit() @@ -63,7 +62,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: # (`-i` is `None`), in order to determine whether to use the default HCI # device (need call `clean_up_running()`) or not need the HCI device at all, # we can use other options to assist the determination. - hci_demander_counter = Counter([args['--clean'], args['--spoof-bd-addr']]) + hci_demander_counter = Counter([args['--clean']]) if hci_demander_counter[True] == 1: if args['-i'] is None: args['-i'] = HCI.get_default_iface() @@ -73,7 +72,7 @@ def parse_cmdline(argv: list[str] = sys.argv[1:]) -> dict: hci.close() if args['BD_ADDR']: - if not verify_bd_addr(args['BD_ADDR']): + if not BD_ADDR.verify(args['BD_ADDR']): raise ValueError("Invalid BD_ADDR: " + red(args['BD_ADDR'])) args['BD_ADDR'] = args['BD_ADDR'].upper() except Exception as e: