This commit is contained in:
anoduck 2023-10-21 16:18:06 -04:00
parent 9c5c1c0660
commit 32e30ea308
4 changed files with 232 additions and 107 deletions

194
ctiger.py
View file

@ -32,6 +32,7 @@ from faker import Faker
# import scapy_ex
# from scapy_ex import Dot11Elt
from art.art import tprint
from dataclasses import dataclass
import struct
import multiprocessing as mp
import asyncio
@ -44,8 +45,9 @@ import socket
import signal
import logging
from time import sleep
sys.path.append(os.path.expanduser('~/.local/lib/python3.11/site-packages'))
# sys.path.append(os.path.expanduser('~/.local/lib/python3.11/site-packages'))
sys.path.append(os.path.expanduser('~/.cache/pypoetry/virtualenvs/crouching-tiger-PCIv_4zN-py3.11/lib/python3.11/site-packages'))
# from simple_parsing import ArgumentParser
# _ _ _ ____ ___ _ ___ _ ___ ___
# \ ( ) / )_\ / _ \ )_ _( )_\ \ _) ) | ) __( ( _(
@ -207,7 +209,7 @@ def strainer(pkt) -> None:
bssid = pkt[Dot11FCS].addr2
log.info('BSSID for strainer: ' + str(bssid))
# iface = get_working_if()
macaddr = NetDev.__dict__['macaddr']
macaddr = Card.mac_addr
log.debug('Local Macaddr is: ', macaddr)
new_pkt = RadioTap()/Dot11(proto=0, type=1, subtype=11,
addr1=bssid,
@ -221,10 +223,15 @@ def strainer(pkt) -> None:
log.info('Intercepted CTS from: ' + bssid)
dbm_signal = pkt.dBm_AntSignal
channel = extract_channel(res[Dot11])
scan_df = Purge.get_df
scan_df.loc[bssid] = ['N/A', dbm_signal, channel, 'N/A']
@dataclass
class Card:
interface: str
mac_addr: str
# -------------------------------------------------------------------
# ███╗ ██╗███████╗████████╗██████╗ ███████╗██╗ ██╗
# ████╗ ██║██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██║
@ -234,22 +241,14 @@ def strainer(pkt) -> None:
# ╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═══╝
# ----------------------------------------------------------------
class NetDev:
def __init__(self) -> None:
self.macaddr = fake.mac_address()
pge = Purge()
self.name = pge.get_name()
self.mon_crtd = str(self.name) + 'mon'
self.mon_type = pge.get_type()
self.channels = pge.get_channels()
def __init__(self, interface, mon_type) -> None:
self.interface = interface
self.mon_type = mon_type
# type: ignore
def get_mac(self) -> str:
return self.macaddr
def create_if(self) -> bool:
def create_if(self, interface, mon_crtd, macaddr) -> bool:
try:
os.system(f'ip link set {self.name} up')
os.system(f'iw dev {self.name} interface add {self.mon_crtd} type monitor')
os.system(f'ip link set {self.interface} up')
os.system(f'iw dev {self.interface} interface add {self.mon_crtd} type monitor')
log.debug('Created ${0}'.format(self.mon_crtd))
os.system(f'ip link set {self.mon_crtd} down')
os.system(f'ip link set {self.mon_crtd} address {self.macaddr}')
@ -261,31 +260,33 @@ class NetDev:
log.info('Device is fully configured and up')
return True
except os.error as e:
log.debug('Failed to create '.format(self.name), e)
log.debug('Failed to create ${0}'.format(self.interface), e)
sys.exit(1)
def switch_if(self) -> bool:
def switch_if(self, interface, macaddress) -> bool:
self.interface = interface
self.macaddr = macaddress
try:
os.system(f'ip link set {self.name} down')
os.system(f'ip link set {self.interface} down')
log.debug('Set device down')
os.system(f'ip link set {self.name} address {self.macaddr}')
os.system(f'ip link set {self.interface} address {self.macaddr}')
log.debug('Set device address to ${0}'.format(self.macaddr))
os.system(f'iw dev {self.name} set type monitor')
log.debug('${0} switched to monitor'.format(self.name))
os.system(f'ip link set {self.name} up')
# (below) setting registry is known to cause issues.
os.system('iw set reg US')
log.debug('Set device registry to US')
scapyconfig.iface = self.name
log.info('Set scapy config self.name to: ${0}'.format(self.name))
os.system(f'iw dev {self.interface} set type monitor')
log.debug('${0} switched to monitor'.format(self.interface))
os.system(f'ip link set {self.interface} up')
scapyconfig.iface = self.interface
log.info('Set scapy config self.name to: ${0}'.format(self.interface))
log.info('Device is fully configured and up')
return True
except os.error as e:
log.debug('Failed to switch ', self.name, ' type', e)
print('Failed to change ', self.name, ' mode', e)
log.debug('Failed to switch ', self.interface, ' type', e)
print('Failed to change ', self.interface, ' mode', e)
sys.exit(1)
def start_monitor(self) -> str:
def start_monitor(self, interface, mon_type) -> str:
"""
Starts a monitor self.name based on the given arguments.
@ -296,23 +297,35 @@ class NetDev:
Returns:
str: The name of the created or switched monitor interface.
"""
macaddr = fake.mac_address()
self.macaddr = macaddr
log.debug('mac_address: ${0}'.format(self.macaddr))
log.debug('Monitor Type: ${0}'.format(self.mon_type))
log.info('Starting monitor interface')
self.interface = interface
self.mon_type = mon_type
mon_crtd = self.interface + 'mon'
self.mon_crtd = mon_crtd
if self.mon_type == 'create':
self.create_if()
mon_if = self.mon_crtd
Card(interface=mon_if, mac_addr=self.macaddr)
return mon_if
elif self.mon_type == 'switch':
self.switch_if()
mon_if = self.name
self.switch_if(self.interface, self.macaddr)
mon_if = self.interface
Card(interface=mon_if, mac_addr=self.macaddr)
return mon_if
else:
Exception('Invalid monitor type')
log.debug('Invalid monitor type')
sys.exit(1)
def channel_runner(self, mon_if) -> None:
def channel_runner(self, mon_if, channels) -> None:
self.mon_if = mon_if
self.channels = channels
log.info('Channel Runner NG started.')
log.info('Preliminary channel list: ${0}'.format(self.channels))
chanlist = self.channels.split(',')
@ -323,17 +336,15 @@ class NetDev:
print(f'name={thread.name}, daemon={thread.daemon}')
while True:
ichan = choice(chans)
os.system(f'iw dev {mon_if} set channel {str(ichan)}')
os.system(f'iw dev {self.mon_if} set channel {str(ichan)}')
# log.debug('Channel set to ', str(ichan))
sleep(14.7)
def signal_handler(signal, frame) -> None:
log = Log.get_log
print('You pressed Ctrl+C!')
log.info('Shutting down')
df2w = Purge.get_df
df2w.to_csv('ct_purge.csv')
scan_df.to_csv('ct_purge.csv')
log.info('Saved results to: ${0}'.format('ct_purge.csv'))
log.info('Going Down!!')
sys.exit(0)
@ -346,41 +357,52 @@ def signal_handler(signal, frame) -> None:
# ██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
# ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝
# -------------------------------------------
class Purge:
@dataclass
class Purge(object):
def __init__(self, **kwargs) -> None:
self.interface = kwargs.get('interface')
self.mon_type = kwargs.get('mon_type')
self.valid_file = kwargs.get('valid_file')
self.channels = kwargs.get('channels')
self.scan_df = DataFrame.get_df
def start_purge(self) -> None:
asyncio.run(self.mac_purge())
asyncio.run(self.mac_purge(self.interface,
self.mon_type,
self.valid_file,
self.channels))
def get_file(self):
return self.valid_file
# def get_file(self):
# return self.valid_file
def get_df(self):
return self.scan_df
# def get_df(self):
# return self.scan_df
def get_channels(self):
return self.channels
# def get_channels(self):
# return self.channels
def get_type(self):
return self.mon_type
# def get_type(self):
# log.debug('Monitor Type: ${0}'.format(self.mon_type))
# return self.mon_type
def get_name(self):
return self.interface
# def get_name(self):
# return self.interface
async def mac_purge(self) -> None:
async def mac_purge(self, interface, mon_type, valid_file, channels):
global scan_df
scan_df = get_df()
self.interface = interface
self.mon_type = mon_type
self.valid_file = valid_file
self.channels = channels
signal.signal(signal.SIGINT, signal_handler)
print('Enter Ctrl+C TWICE to fully stop the script.')
dev = NetDev()
mon_if = dev.start_monitor()
ndev = NetDev(interface=self.interface, mon_type=self.mon_type)
mon_if = ndev.start_monitor(interface=self.interface,
mon_type=self.mon_type)
log.info('interface ${0} is up and running.'.format(mon_if))
# vfile = self.get_file()
# log.info('We will be writing captured macs to ', str(self.valid_file))
chop = asyncio.to_thread(dev.channel_runner(mon_if)) # type: ignore
chop = asyncio.to_thread(ndev.channel_runner(mon_if, self.channels)) # type: ignore
chopper = asyncio.create_task(chop)
log.info('Channel runner started.')
await asyncio.sleep(0)
@ -588,55 +610,29 @@ def scan_scn(interface, save_results, rfile):
# ╚██████╔╝███████╗ ██║ ██████╔╝██║
# ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝
# -------------------------------------------------------------
class DataFrame:
def get_df():
"""
Initializes and returns an empty pandas DataFrame object.
This function creates a new pandas DataFrame object, `scan_df`, with the following columns:
- `BSSID`: The BSSID of the WiFi network.
- `SSID`: The SSID of the WiFi network.
- `dBm_Signal`: The signal strength of the WiFi network in dBm.
- `Channel`: The channel of the WiFi network.
- `Crypto`: The encryption type of the WiFi network.
The function sets the index of the DataFrame to be the `BSSID` column.
Initializes a new empty DataFrame for storing scan data.
Returns:
scan_df (pandas DataFrame): An empty DataFrame object with the specified columns and index.
pandas.DataFrame: The newly created DataFrame with columns 'BSSID', 'SSID', 'dBm_Signal', 'Channel', and 'Crypto'.
"""
def __init__(self, scan_df):
self.scan_df = scan_df
def get_df(self):
"""
Initializes a new empty DataFrame for storing scan data.
Returns:
pandas.DataFrame: The newly created DataFrame with columns 'BSSID', 'SSID', 'dBm_Signal', 'Channel', and 'Crypto'.
"""
self.scan_df = pd.DataFrame(columns=['BSSID', 'SSID',
'dBm_Signal', 'Channel',
'Crypto'])
self.scan_df.set_index("BSSID", inplace=True)
return self.scan_df
scan_df = pd.DataFrame(columns=['BSSID', 'SSID',
'dBm_Signal', 'Channel',
'Crypto'])
scan_df.set_index("BSSID", inplace=True)
return scan_df
def get_log():
log_file = os.path.abspath('/var/log/ctiger.log')
# logging.basicConfig(filename=log_file, level=args.log_level,
# format='%(asctime)s %(levelname)s %(message)s')
# create logger
scapy_logger = logging.getLogger('scapy.runtime')
global log
log = logging.getLogger(__name__)
scapy_logger.setLevel(logging.DEBUG)
def get_log(log_file):
logfile = os.path.abspath(log_file)
log = logging.getLogger('scapy.runtime')
if log.hasHandlers():
log.handlers.clear()
log.setLevel(logging.DEBUG)
handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler = logging.FileHandler(logfile, mode='a', encoding='utf-8')
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
scapy_logger.addHandler(handler)
log.addHandler(handler)
log.info('Started crouching tiger')
log.info('Started logger...')
@ -662,8 +658,8 @@ def process_args(args: argparse.Namespace) -> None:
Returns:
None
"""
log = get_log()
global log
log = get_log(args.log_file)
log.info('Started crouching tiger')
log.info('Started logger...')
match args.module:
@ -674,6 +670,7 @@ def process_args(args: argparse.Namespace) -> None:
log.info('Beginning Mac Purge')
#mon_dev, mon_type, valid_file, channels
#mon_dev, mon_type, valid_file, channels
log.debug('args: ${0}'.format(args))
pge = Purge(interface=args.name,
mon_type=args.mon_type,
valid_file=args.valid_file,
@ -814,7 +811,7 @@ else:
mac_parse.add_argument('-c', '--channels', dest='channels',
default=config['MAC_PURGE']['channel_list'],
help='A single or comma seperated list of channels.')
mac_parse.set_defaults(fun=Purge.mac_purge)
mac_parse.set_defaults(fun=Purge.start_purge)
# scn Subcommands
scn_parse = subparse.add_parser('scn', help='Scan for target')
@ -830,6 +827,7 @@ else:
##################
# parse the args #
##################
ap.set_defaults(fun=process_args)
args = ap.parse_args(args=None if sys.argv[1:] else ['--help'])
process_args(args)

View file

@ -1704,7 +1704,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scapy Examples from popular programs (Circa 2018)\n",
"## Scapy Examples from popular programs (Circa 2018)\n",
"\n",
"Below are examples of popular scapy functions."
]
@ -1713,7 +1713,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1. Aggr-Inject"
"### 1. Aggr-Inject"
]
},
{
@ -1735,7 +1735,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2. Aggr-Inject"
"### 2. Aggr-Inject"
]
},
{
@ -1758,7 +1758,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3. Aggr-Inject"
"### 3. Aggr-Inject"
]
},
{
@ -1781,7 +1781,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 4. Pyrit"
"### 4. Pyrit"
]
},
{
@ -1848,7 +1848,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 5. Aggr-Inject"
"### 5. Aggr-Inject"
]
},
{
@ -1901,11 +1901,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"### Calculating distance of a wireless device\n",
"## Calculating distance of a wireless device\n",
"\n",
"This is where I wish I had payed more attention in math class.\n",
"\n",
"#### Calculating Frame Margin. (or whatever FSPL is.)\n",
"### Calculating Frame Margin. (or whatever FSPL is.)\n",
"\n",
"`FSPL (dB) = 20log10(d) + 20log10(f) + K`\n",
"\n",
@ -1920,6 +1920,49 @@
"\n",
"FSPL = Tx Power - Tx CBLS + Tx AntGain + Rx AntGain - RxCBLS - Rx Sensitivity - Fade Margin"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Debuging Output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"```shell\n",
" █▀▀█ █▀▀█ █▀▀█ █──█ █▀▀ █──█ ─▀─ █▀▀▄ █▀▀▀ ▀▀█▀▀ ─▀─ █▀▀▀ █▀▀ █▀▀█\n",
"░█─── █▄▄▀ █──█ █──█ █── █▀▀█ ▀█▀ █──█ █─▀█ ─░█── ▀█▀ █─▀█ █▀▀ █▄▄▀\n",
"░█▄▄█ ▀─▀▀ ▀▀▀▀ ─▀▀▀ ▀▀▀ ▀──▀ ▀▀▀ ▀──▀ ▀▀▀▀ ─░█── ▀▀▀ ▀▀▀▀ ▀▀▀ ▀─▀▀\n",
"INFO: Started crouching tiger\n",
"INFO: Started logger...\n",
"INFO: Started crouching tiger\n",
"INFO: Started logger...\n",
"INFO: Beginning Mac Purge\n",
"DEBUG: args: $Namespace(name='wlan0', config_file='config_path', log_level='DEBUG', log_file='/var/log/ctiger.log', module='mac', mon_type='switch', valid_file='ct_valid.csv', channels='1,7,6,11', fun=<function Purge.mac_purge at 0x7f9166405a80>)\n",
"DEBUG: Kwargs: ${'name': 'wlan0', 'config_file': 'config_path', 'log_level': 'DEBUG', 'log_file': '/var/log/ctiger.log', 'module': 'mac', 'mon_type': 'switch', 'valid_file': 'ct_valid.csv', 'channels': '1,7,6,11', 'fun': <function Purge.mac_purge at 0x7f9166405a80>}\n",
"DEBUG: Interface: $None\n",
"DEBUG: Self Interface: $None\n",
"DEBUG: Monitor Type: $switch\n",
"DEBUG: Kwargs: ${'interface': 'wlan0', 'mon_type': 'switch', 'valid_file': 'ct_valid.csv', 'channels': '1,7,6,11'}\n",
"DEBUG: Interface: $wlan0\n",
"DEBUG: Self Interface: $wlan0\n",
"DEBUG: Monitor Type: $switch\n",
"DEBUG: Kwargs: ${}\n",
"DEBUG: Interface: $None\n",
"DEBUG: Self Interface: $None\n",
"DEBUG: Monitor Type: $None\n",
"DEBUG: Monitor Type:\n",
"DEBUG: mac_address: $3d:1d:06:fd:9b:e1\n",
"DEBUG: Monitor Type: $None\n",
"INFO: Starting monitor interface\n",
"DEBUG: Invalid monitor type\n",
"```"
]
}
],
"metadata": {

85
poetry.lock generated
View file

@ -62,6 +62,17 @@ files = [
{file = "daemonize-2.5.0.tar.gz", hash = "sha256:dd026e4ff8d22cb016ed2130bc738b7d4b1da597ef93c074d2adb9e4dea08bc3"},
]
[[package]]
name = "docstring-parser"
version = "0.15"
description = "Parse Python docstrings in reST, Google and Numpydoc format"
optional = false
python-versions = ">=3.6,<4.0"
files = [
{file = "docstring_parser-0.15-py3-none-any.whl", hash = "sha256:d1679b86250d269d06a99670924d6bce45adc00b08069dae8c47d98e89b667a9"},
{file = "docstring_parser-0.15.tar.gz", hash = "sha256:48ddc093e8b1865899956fcc03b03e66bb7240c310fac5af81814580c55bf682"},
]
[[package]]
name = "faker"
version = "13.16.0"
@ -139,6 +150,47 @@ files = [
{file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
]
[[package]]
name = "numpy"
version = "1.26.1"
description = "Fundamental package for array computing in Python"
optional = false
python-versions = "<3.13,>=3.9"
files = [
{file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"},
{file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"},
{file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"},
{file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"},
{file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"},
{file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"},
{file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"},
{file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"},
{file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"},
{file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"},
{file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"},
{file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"},
{file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"},
{file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"},
{file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"},
{file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"},
{file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"},
{file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"},
{file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"},
{file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"},
{file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"},
{file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"},
{file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"},
{file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"},
{file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"},
{file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"},
]
[[package]]
name = "pandas"
version = "2.1.0"
@ -301,6 +353,26 @@ basic = ["ipython"]
complete = ["cryptography (>=2.0)", "ipython", "matplotlib", "pyx"]
docs = ["sphinx (>=3.0.0)", "sphinx_rtd_theme (>=0.4.3)", "tox (>=3.0.0)"]
[[package]]
name = "simple-parsing"
version = "0.1.4"
description = "A small utility for simplifying and cleaning up argument parsing scripts."
optional = false
python-versions = ">=3.7"
files = [
{file = "simple_parsing-0.1.4-py3-none-any.whl", hash = "sha256:1fb042499d8872090ed3aad1f60f4d53026d2062942196a600933bc83787328e"},
{file = "simple_parsing-0.1.4.tar.gz", hash = "sha256:312300327d8f0beb61b6419500423bd335be8b83da66f733e9c67c6c18341ae8"},
]
[package.dependencies]
docstring-parser = ">=0.15,<1.0"
typing-extensions = ">=4.5.0"
[package.extras]
all = ["numpy", "pytest", "pytest-benchmark", "pytest-regressions", "pytest-xdist", "pyyaml"]
test = ["numpy", "pytest", "pytest-benchmark", "pytest-regressions", "pytest-xdist"]
yaml = ["pyyaml"]
[[package]]
name = "six"
version = "1.16.0"
@ -312,6 +384,17 @@ files = [
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[[package]]
name = "typing-extensions"
version = "4.8.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
]
[[package]]
name = "tzdata"
version = "2023.3"
@ -326,4 +409,4 @@ files = [
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "fe0ddb56e36b45960c6cd428789caed368f5ce252415cfebb66758a674e65d24"
content-hash = "04596bf28419e3f62541cfe785f8cba26bfab7e5e44f31efbe737947c39324ec"

View file

@ -18,6 +18,7 @@ daemon = "^1.2"
daemonize = "^2.5.0"
getmac = "^0.9.4"
faker-wifi-essid = "^0.4.1"
simple-parsing = "^0.1.4"
[build-system]