Skip to content

Commit

Permalink
MacOS support
Browse files Browse the repository at this point in the history
  • Loading branch information
needs-coffee committed Mar 31, 2021
1 parent 75ccc6e commit f906616
Show file tree
Hide file tree
Showing 7 changed files with 426 additions and 12 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@ On linux reads the NetworkManager files or wpa_supplicant.conf.
Cross platform:
- Windows
- Linux
- macOS (to be implemented)
- macOS (working - however see below note)

**NOTE:** requires sudo privileges on linux only if NetworkManager is not used.
**NOTE:** requires sudo privileges on linux only if NetworkManager is not used.

**NOTE:** Macos requires admin authentication for each password read, this can result in a lot of prompts for the get_passwords() function. I am currently looking for a solution for this.

Features
--------
- Importable as a package or able to be run directly on the command line
- Tested in Python 3.6 - 3.9
- Tested on Windows 10, Ubuntu 18 - 20.04 and Debian Buster
- Tested on Windows 10, Ubuntu 18 - 20.04, Debian Buster, macOS 10.13 (High Sierra) and macOS 10.14 (Mojave)
- Returns WiFi passwords as a dictionary
- Able to show visible wifi networks
- Able to show currently connected SSID
- Able to show current DNS config
- Able to show known SSIDs and find single network passwords
- Can save networks as JSON or wpa_supplicant.conf file

Installation
Expand Down Expand Up @@ -64,7 +67,8 @@ The wifipasswords_exe.py file is the same as the __main__.py file in the package

To-Do
-----
- [ ] Add macOS Support
- [X] Add macOS Support
- [ ] Improve mac authentication methods
- [X] Add getters for accessing variables directly
- [X] Fix visible network, DNS config and number of interfaces for Linux
- [ ] Add automated tests
Expand All @@ -76,7 +80,7 @@ To-Do
About
-----
Creation date: 10-02-2019
Modified date: 26-03-2021
Modified date: 30-03-2021
Dependencies: colorama


Expand Down
7 changes: 6 additions & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.3.5b - 28-03-2021
## 0.4.0b - 30-03-2021
### Added
- MacOS support added
- addded get_known_ssids() function
- addeed get_single_password() function


## 0.3.5b - 28-03-2021
### Changed
- Fix for detecting current network if NetworkManager not installed
- Other bugfixes.
Expand Down
23 changes: 20 additions & 3 deletions wifipasswords/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Uses the netsh windows module. Pass --JSON argument to export as JSON.
Pass --wpasupplicant to create a wpa_supplicant.conf file for linux
Creation date: 10-02-2019
Modified date: 26-03-2021
Modified date: 30-03-2021
Dependencies: colorama
"""
__copyright__ = "Copyright (C) 2019-2021 Joe Campbell"
Expand All @@ -25,7 +25,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see < https: // www.gnu.org/licenses/>.

__version__ = "0.3.5-beta"
__version__ = "0.4.0-beta"
__licence__ = "GPLv3" # GNU General Public Licence v3

import platform
Expand All @@ -46,7 +46,8 @@ def __init__(self) -> None:
from .wifipasswords_linux import WifiPasswordsLinux as _PlatformClass
self._WifiPasswordsSubclass = _PlatformClass()
elif self.platform == 'Darwin':
raise NotImplementedError
from .wifipasswords_macos import WifiPasswordsMacos as _PlatformClass
self._WifiPasswordsSubclass = _PlatformClass()
elif self.platform == 'Java':
raise NotImplementedError
else:
Expand Down Expand Up @@ -197,3 +198,19 @@ def get_currently_connected_passwords(self) -> list:
Returns a tuple of (ssid, psk) for each currently connected network as a list.
"""
return self._WifiPasswordsSubclass.get_currently_connected_passwords()


def get_known_ssids(self) -> list:
"""
Returns a list of known SSIDs without password information.
"""
return self._WifiPasswordsSubclass.get_known_ssids()


def get_single_password(self,ssid) -> str:
"""
Returns the psk for the specified SSID.\n
If the SSID is open, returns None. \n
if the SSID is not found raises a ValueError \n
"""
return self._WifiPasswordsSubclass.get_single_password(ssid)
62 changes: 61 additions & 1 deletion wifipasswords/wifipasswords_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import os
import json
import re
from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing.dummy import Pool as ThreadPool, Value

from . import __version__, __copyright__, __licence__

Expand Down Expand Up @@ -359,3 +359,63 @@ def get_currently_connected_passwords(self) -> list:
connected_passwords.append((ssid, psk))

return connected_passwords


def get_known_ssids(self) -> list:
ssids = []
## check network manager first, if configured dont check wpa_supplicant file
# if the path doesnt exist then NetworkManager prob isnt installed/configured.
if os.path.exists(self.nm_path):
profiles_list = self._command_runner(['nmcli', '-t', '-f', 'NAME,TYPE', 'c']).split('\n')
ssids = [re.split(r"(?<!\\):", ssid)[0] for ssid in profiles_list if '802-11-wireless' in ssid]

## check wpa_supplicant file, but only if the file exists and no networks were found from networkmanager
# if network manager is being used there shouldn't be an active wpa_supplicant file
elif os.path.isfile(self.wpa_supplicant_file_path):
file_string = self._command_runner(['sudo', 'cat', self.wpa_supplicant_file_path])
network_blocks = re.findall('(?<=network={)[^}]*(?=})', file_string)
for network_block in network_blocks:
block_stripped = network_block.strip().replace('\t', '').split('\n')
ssid = ' '
for item in block_stripped:
if 'ssid' in item:
ssid = item.split('ssid=')[1][1:-1]
ssids.append(ssid)
else:
ssids = []

self.number_of_profiles = len(ssids)
return ssids


def get_single_password(self, ssid) -> str:
psk = ''
found = False
if os.path.exists(self.nm_path):
key_content = self._command_runner(['nmcli', '-t', '-f',
'802-11-wireless-security.psk,connection.id', 'c', 's', ssid, '--show-secrets'])
if key_content == '':
raise ValueError('SSID not known.')
else:
found = True

for row in key_content.split('\n'):
if '802-11-wireless-security.psk' in row:
psk = row.split(':')[1]

elif os.path.isfile(self.wpa_supplicant_file_path):
file_string = self._command_runner(['sudo', 'cat', self.wpa_supplicant_file_path])
network_blocks = re.findall('(?<=network=)[^}]*(?=})', file_string)

for network_block in network_blocks:
if ssid in network_block:
found = True
stripped_block = network_block.strip().replace(
'\t', '').replace('\n', ' ').split(' ')
for row in stripped_block:
if 'psk' in row:
psk = row.split('psk=')[1][1:-1]
if found:
return psk
else:
raise ValueError('SSID not known.')
Loading

0 comments on commit f906616

Please sign in to comment.