Skip to content

Conversation

@sourcery-ai
Copy link

@sourcery-ai sourcery-ai bot commented Feb 20, 2022

Branch main refactored by Sourcery.

If you're happy with these changes, merge this Pull Request using the Squash and merge strategy.

See our documentation here.

Run Sourcery locally

Reduce the feedback loop during development by using the Sourcery editor plugin:

Review changes via command line

To manually merge these changes, make sure you're on the main branch, then run:

git fetch origin sourcery/main
git merge --ff-only FETCH_HEAD
git reset HEAD^

Help us improve this pull request!

@sourcery-ai sourcery-ai bot requested a review from eysteing February 20, 2022 22:59
def in_sudo_mode():
"""If the user doesn't run the program with super user privileges, don't allow them to continue."""
if not 'SUDO_UID' in os.environ.keys():
if 'SUDO_UID' not in os.environ.keys():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function in_sudo_mode refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

Comment on lines -34 to +39
# We create an empty list where we will store the pairs of ARP responses.
arp_responses = list()
# We send arp packets through the network, verbose is set to 0 so it won't show any output.
# scapy's arping function returns two lists. We're interested in the answered results which is at the 0 index.
answered_lst = scapy.arping(ip_range, verbose=0)[0]

# We loop through all the responses and add them to a dictionary and append them to the list arp_responses.
for res in answered_lst:
# Every response will look something lke like -> {"ip" : "10.0.0.4", "mac" : "00:00:00:00:00:00"}
arp_responses.append({"ip" : res[1].psrc, "mac" : res[1].hwsrc})


# We return the list of arp responses which contains dictionaries for every arp response.
return arp_responses
return [{"ip" : res[1].psrc, "mac" : res[1].hwsrc} for res in answered_lst]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function arp_scan refactored with the following changes:

This removes the following comments ( why? ):

# We loop through all the responses and add them to a dictionary and append them to the list arp_responses.
# Every response will look something lke like -> {"ip" : "10.0.0.4", "mac" : "00:00:00:00:00:00"}
# We create an empty list where we will store the pairs of ARP responses.

Comment on lines -55 to +48
# Loop through every row in the route -n command.
for row in result:
# We look to see if the gateway_ip is in the row, if it is we return True. If False program continues flow and returns False.
if gateway_ip in row:
return True

return False
return any(gateway_ip in row for row in result)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function is_gateway refactored with the following changes:

  • Use any() instead of for loop (use-any)

This removes the following comments ( why? ):

# Loop through every row in the route -n command.
# We look to see if the gateway_ip is in the row, if it is we return True. If False program continues flow and returns False.

Comment on lines -68 to +56
# We use the listdir() function from the os module. Since we know there won't be files and only directories with the interface names we can save the output as the interface names.
interface_names = os.listdir()
# We return the interface names which we will use to find out which one is the name of the gateway.
return interface_names
return os.listdir()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function get_interface_names refactored with the following changes:

This removes the following comments ( why? ):

# We use the listdir() function from the os module. Since we know there won't be files and only directories with the interface names we can save the output as the interface names.

Comment on lines -112 to +97
for item in arp_res:
# All items which are not the gateway will be appended to the client_list.
if gateway["ip"] != item["ip"]:
client_list.append(item)
client_list.extend(item for item in arp_res if gateway["ip"] != item["ip"])
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function clients refactored with the following changes:

This removes the following comments ( why? ):

# All items which are not the gateway will be appended to the client_list.

Comment on lines -46 to +48
port_range_valid = port_range_pattern.search(port_range.replace(" ",""))
if port_range_valid:
if port_range_valid := port_range_pattern.search(
port_range.replace(" ", "")
):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 46-47 refactored with the following changes:


# If the user doesn't run the program with super user privileges, don't allow them to continue.
if not 'SUDO_UID' in os.environ.keys():
if 'SUDO_UID' not in os.environ.keys():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 58-78 refactored with the following changes:

def in_sudo_mode():
"""If the user doesn't run the program with super user privileges, don't allow them to continue."""
if not 'SUDO_UID' in os.environ.keys():
if 'SUDO_UID' not in os.environ.keys():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function in_sudo_mode refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

result = subprocess.run(["iw", "dev"], capture_output=True).stdout.decode()
network_interface_controllers = wlan_code.findall(result)
return network_interface_controllers
return wlan_code.findall(result)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function find_nic refactored with the following changes:

Comment on lines -79 to +84
os.mkdir(directory + "/backup/")
os.mkdir(f'{directory}/backup/')
except:
print("Backup folder exists.")
# Create a timestamp
timestamp = datetime.now()
# We copy any .csv files in the folder to the backup folder.
shutil.move(file_name, directory + "/backup/" + str(timestamp) + "-" + file_name)
shutil.move(file_name, f'{directory}/backup/{str(timestamp)}-{file_name}')
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function backup_csv refactored with the following changes:

Comment on lines -107 to +127
active_wireless_networks = list()
active_wireless_networks = []
try:
while True:
# We want to clear the screen before we print the network interfaces.
subprocess.call("clear", shell=True)
for file_name in os.listdir():
if ".csv" in file_name:
# We should only have one csv file as we backup all previous csv files from the folder every time we run the program.
# The following list contains the field names for the csv entries.
fieldnames = ['BSSID', 'First_time_seen', 'Last_time_seen', 'channel', 'Speed', 'Privacy', 'Cipher', 'Authentication', 'Power', 'beacons', 'IV', 'LAN_IP', 'ID_length', 'ESSID', 'Key']
if ".csv" in file_name:
with open(file_name) as csv_h:
# We use the DictReader method and tell it to take the csv_h contents and then apply the dictionary with the fieldnames we specified above.
# This creates a list of dictionaries with the keys as specified in the fieldnames.
csv_h.seek(0)
csv_reader = csv.DictReader(csv_h, fieldnames=fieldnames)
for row in csv_reader:
if row["BSSID"] == "BSSID":
pass
elif row["BSSID"] == "Station MAC":
break
elif check_for_essid(row["ESSID"], active_wireless_networks):
active_wireless_networks.append(row)
with open(file_name) as csv_h:
# We use the DictReader method and tell it to take the csv_h contents and then apply the dictionary with the fieldnames we specified above.
# This creates a list of dictionaries with the keys as specified in the fieldnames.
csv_h.seek(0)
csv_reader = csv.DictReader(csv_h, fieldnames=fieldnames)
for row in csv_reader:
if row["BSSID"] == "BSSID":
pass
elif row["BSSID"] == "Station MAC":
break
elif check_for_essid(row["ESSID"], active_wireless_networks):
active_wireless_networks.append(row)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function wifi_networks_menu refactored with the following changes:

Comment on lines -200 to +199
macs_not_to_kick_off = list()
macs_not_to_kick_off = []
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 200-310 refactored with the following changes:

This removes the following comments ( why? ):

# We will not add the MAC Addresses we specified at the beginning of the program to the ones we will kick off.


# If the user doesn't run the program with super user privileges, don't allow them to continue.
if not 'SUDO_UID' in os.environ.keys():
if 'SUDO_UID' not in os.environ.keys():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 59-192 refactored with the following changes:


# If the user doesn't run the program with super user privileges, don't allow them to continue.
if not 'SUDO_UID' in os.environ.keys():
if 'SUDO_UID' not in os.environ.keys():
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 57-193 refactored with the following changes:

Comment on lines -21 to +45
wifi_list = list()
wifi_list = []


# If we didn't find profile names we didn't have any wifi connections, so we only run the part to check for the details of the wifi and whether we can get their passwords in this part.
if len(profile_names) != 0:
for name in profile_names:
# Every wifi connection will need its own dictionary which will be appended to the wifi_list
wifi_profile = dict()
# We now run a more specific command to see the information about the specific wifi connection and if the Security key is not absent we can possibly get the password.
profile_info = subprocess.run(["netsh", "wlan", "show", "profile", name], capture_output = True).stdout.decode()
# We use a regular expression to only look for the absent cases so we can ignore them.
if re.search("Security key : Absent", profile_info):
continue
else:
# Assign the ssid of the wifi profile to the dictionary
wifi_profile["ssid"] = name
# These cases aren't absent and we should run them "key=clear" command part to get the password
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expressions to capture the group after the : which is the password
password = re.search("Key Content : (.*)\r", profile_info_pass)
wifi_profile = {'ssid': name}
# These cases aren't absent and we should run them "key=clear" command part to get the password
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expressions to capture the group after the : which is the password
password = re.search("Key Content : (.*)\r", profile_info_pass)
# Check if we found a password in the regular expression. All wifi connections will not have passwords.
if password == None:
wifi_profile["password"] = None
else:
# We assign the grouping (Where the password is contained) we are interested to the password key in the dictionary.
wifi_profile["password"] = password[1]
# We append the wifi information to the wifi_list
wifi_list.append(wifi_profile)
wifi_profile["password"] = None if password is None else password[1]
# We append the wifi information to the wifi_list
wifi_list.append(wifi_profile)

# Create the message for the email
email_message = ""
for item in wifi_list:
email_message += f"SSID: {item['ssid']}, Password: {item['password']}\n"
email_message = "".join(
f"SSID: {item['ssid']}, Password: {item['password']}\n"
for item in wifi_list
)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 21-53 refactored with the following changes:

This removes the following comments ( why? ):

# Assign the ssid of the wifi profile to the dictionary
# Every wifi connection will need its own dictionary which will be appended to the wifi_list
# We use a regular expression to only look for the absent cases so we can ignore them.
# We assign the grouping (Where the password is contained) we are interested to the password key in the dictionary.

Comment on lines -20 to +38
wifi_list = list()
wifi_list = []


# If we didn't find profile names we didn't have any wifi connections, so we only run the part to check for the details of the wifi and whether we can get their passwords in this part.
if len(profile_names) != 0:
for name in profile_names:
# Every wifi connection will need its own dictionary which will be appended to the wifi_list
wifi_profile = dict()
# We now run a more specific command to see the information about the specific wifi connection and if the Security key is not absent we can possibly get the password.
profile_info = subprocess.run(["netsh", "wlan", "show", "profile", name], capture_output = True).stdout.decode()
# We use a regular expression to only look for the absent cases so we can ignore them.
if re.search("Security key : Absent", profile_info):
continue
else:
# Assign the SSID of the wifi profile to the dictionary
wifi_profile["ssid"] = name
# These cases aren't absent and we should run them "key=clear" command part to get the password
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expressions to capture the group after the : which is the password
password = re.search("Key Content : (.*)\r", profile_info_pass)
wifi_profile = {'ssid': name}
# These cases aren't absent and we should run them "key=clear" command part to get the password
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expressions to capture the group after the : which is the password
password = re.search("Key Content : (.*)\r", profile_info_pass)
# Check if we found a password in the regular expression. All wifi connections will not have passwords.
if password == None:
wifi_profile["password"] = None
else:
# We assign the grouping (Where the password is contained) we are interested to the password key in the dictionary.
wifi_profile["password"] = password[1]
# We append the wifi information to the wifi_list
wifi_list.append(wifi_profile)
wifi_profile["password"] = None if password is None else password[1]
# We append the wifi information to the wifi_list
wifi_list.append(wifi_profile)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 20-47 refactored with the following changes:

This removes the following comments ( why? ):

# Every wifi connection will need its own dictionary which will be appended to the wifi_list
# We use a regular expression to only look for the absent cases so we can ignore them.
# We assign the grouping (Where the password is contained) we are interested to the password key in the dictionary.
# Assign the SSID of the wifi profile to the dictionary

Comment on lines -44 to +64
# Every wifi connection will need its own dictionary which
# will be appended to the variable wifi_list.
wifi_profile = {}
# We can now run a more specific command to see the information
# about the wifi connection and if the Security key
# is not absent it may be possible to get the password.
profile_info = subprocess.run(["netsh", "wlan", "show", "profile", name], capture_output = True).stdout.decode()
# We use the regular expression to only look for the absent cases so we can ignore them.
if re.search("Security key : Absent", profile_info):
continue
else:
# Assign the ssid of the wifi profile to the dictionary.
wifi_profile["ssid"] = name
# These cases aren't absent and we should run the
# "key=clear" command part to get the password.
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expression to capture the
# group after the : (which is the password).
password = re.search("Key Content : (.*)\r", profile_info_pass)
wifi_profile = {'ssid': name}
# These cases aren't absent and we should run the
# "key=clear" command part to get the password.
profile_info_pass = subprocess.run(["netsh", "wlan", "show", "profile", name, "key=clear"], capture_output = True).stdout.decode()
# Again run the regular expression to capture the
# group after the : (which is the password).
password = re.search("Key Content : (.*)\r", profile_info_pass)
# Check if we found a password using the regular expression.
# Some wifi connections may not have passwords.
if password == None:
wifi_profile["password"] = None
else:
# We assign the grouping (where the password is contained) that
# we are interested in to the password key in the dictionary.
wifi_profile["password"] = password[1]
# We append the wifi information to the variable wifi_list.
wifi_list.append(wifi_profile)
wifi_profile["password"] = None if password is None else password[1]
# We append the wifi information to the variable wifi_list.
wifi_list.append(wifi_profile)

for x in range(len(wifi_list)):
print(wifi_list[x])
for wifi in wifi_list:
print(wifi)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 44-75 refactored with the following changes:

This removes the following comments ( why? ):

#    We use the regular expression to only look for the absent cases so we can ignore them.
#    will be appended to the variable wifi_list.
#    we are interested in to the password key in the dictionary.
#    Every wifi connection will need its own dictionary which
#    We assign the grouping (where the password is contained) that
#    Assign the ssid of the wifi profile to the dictionary.

@sourcery-ai
Copy link
Author

sourcery-ai bot commented Feb 20, 2022

Sourcery Code Quality Report

✅  Merging this PR will increase code quality in the affected files by 0.14%.

Quality metrics Before After Change
Complexity 24.50 😞 24.34 😞 -0.16 👍
Method Length 99.57 🙂 97.94 🙂 -1.63 👍
Working memory 11.57 😞 11.51 😞 -0.06 👍
Quality 40.60% 😞 40.74% 😞 0.14% 👍
Other metrics Before After Change
Lines 1962 1925 -37
Changed files Quality Before Quality After Quality Change
arp_mitm.py 82.65% ⭐ 83.24% ⭐ 0.59% 👍
change-windows10-mac-address.py 11.68% ⛔ 12.28% ⛔ 0.60% 👍
exif.py 29.60% 😞 29.73% 😞 0.13% 👍
exif_csv.py 36.56% 😞 36.72% 😞 0.16% 👍
nmap_port_scanner.py 54.68% 🙂 54.77% 🙂 0.09% 👍
nmap_port_scanner_ip_obj.py 54.97% 🙂 55.07% 🙂 0.10% 👍
port_scanner_ip_obj.py 51.99% 🙂 52.09% 🙂 0.10% 👍
port_scanner_regex.py 51.99% 🙂 52.09% 🙂 0.10% 👍
wifi_dos3.py 26.79% 😞 26.79% 😞 0.00%
wifi_dos_own.py 41.05% 😞 41.27% 😞 0.22% 👍
wifi_dos_type1.py 24.94% ⛔ 24.93% ⛔ -0.01% 👎
wifi_dos_type2.py 23.56% ⛔ 23.54% ⛔ -0.02% 👎
windows10-wifi-email.py 39.88% 😞 45.53% 😞 5.65% 👍
windows10-wifi-rest.py 42.59% 😞 47.65% 😞 5.06% 👍
windows10-wifi.py 49.39% 😞 55.41% 🙂 6.02% 👍

Here are some functions in these files that still need a tune-up:

File Function Complexity Length Working Memory Quality Recommendation
wifi_dos_own.py wifi_networks_menu 23 😞 168 😞 10 😞 41.19% 😞 Refactor to reduce nesting. Try splitting into smaller methods. Extract out complex expressions

Legend and Explanation

The emojis denote the absolute quality of the code:

  • ⭐ excellent
  • 🙂 good
  • 😞 poor
  • ⛔ very poor

The 👍 and 👎 indicate whether the quality has improved or gotten worse with this pull request.


Please see our documentation here for details on how these metrics are calculated.

We are actively working on this report - lots more documentation and extra metrics to come!

Help us improve this quality report!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant