├── .gitignore ├── requirements.txt ├── wifi_password ├── __init__.py ├── __main__.py ├── constants.py ├── wifi_password.py └── utils.py ├── images └── demo.gif ├── .github └── FUNDING.yml ├── setup.py ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | dist 3 | *.egg-info 4 | build/ 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | qrcode 2 | image 3 | Pillow 4 | colorama 5 | -------------------------------------------------------------------------------- /wifi_password/__init__.py: -------------------------------------------------------------------------------- 1 | from .wifi_password import main 2 | -------------------------------------------------------------------------------- /wifi_password/__main__.py: -------------------------------------------------------------------------------- 1 | from wifi_password import main 2 | 3 | main() 4 | -------------------------------------------------------------------------------- /images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sdushantha/wifi-password/HEAD/images/demo.gif -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | custom: https://www.buymeacoffee.com/sdushantha 3 | -------------------------------------------------------------------------------- /wifi_password/constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Platfrom Names 4 | LINUX = 'Linux' 5 | MAC = 'MacOS' 6 | WINDOWS = 'Windows' 7 | 8 | # MacOS Airport package path 9 | AIRPORT_PATH = "/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport" -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r", encoding="utf-8") as f: 4 | long_description = f.read() 5 | 6 | setuptools.setup( 7 | name="wifi-password", 8 | version="1.1.1", 9 | author="Siddharth Dushantha", 10 | author_email="siddharth.dushantha@gmail.com", 11 | description="Quickly fetch your WiFi password and if needed, generate a QR code of your WiFi to allow phones to easily connect", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/sdushantha/wifi-password", 15 | packages=setuptools.find_packages(), 16 | entry_points={"console_scripts": ["wifi-password = wifi_password.wifi_password:main"]}, 17 | install_requires=["qrcode", "image", "Pillow", "colorama"], 18 | ) 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Siddharth Dushantha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | wifi-password 3 |

4 |

5 | Quickly fetch your WiFi password and if needed, generate a QR code of your WiFi to allow phones to easily connect. 6 |
7 | Works on macOS and Linux, Windows 8 | 9 |

10 | 11 | ## Installation 12 | 13 | ### Install using `pip` 14 | ```console 15 | $ python3 -m pip install --user wifi-password 16 | ``` 17 | 18 | ### Install using `git` 19 | ``` 20 | $ git clone https://github.com/sdushantha/wifi-password 21 | $ cd wifi-password 22 | $ python3 setup.py install 23 | ``` 24 | 25 | ### Install using the [AUR](https://aur.archlinux.org/packages/wifi-password/) 26 | - With `pamac` 27 | ```console 28 | $ sudo pamac build wifi-password 29 | ``` 30 | - With `yay` 31 | ```console 32 | $ yay -S wifi-password 33 | ``` 34 | 35 | --- 36 | --- 37 | ## Usage 38 | ```console 39 | $ wifi-password --help 40 | usage: wifi_password [options] 41 | 42 | optional arguments: 43 | -h, --help show this help message and exit 44 | --show-qr, -show Show a ASCII QR code onto the terminal/console 45 | --save-qr [PATH], -save [PATH] 46 | Create the QR code and save it as an image 47 | --ssid SSID, -s SSID Specify a SSID that you have previously connected to 48 | --list, -l Lists all stored network SSID 49 | --version Show version number 50 | ``` 51 | 52 | --- 53 | --- 54 | ## Problems? Check this list 55 | - ### Password not found: 56 | - **Linux:** 57 | - Make sure your network passwords are stored correctly in NetworkManager's storage directory. This is in /etc/NetworkManager/system-connections/. NetworkManager can work by checking if the passwords are stored with another program, but you need to store them in this directory for this program to work. 58 | - **MacOS/Windows:** 59 | - You probably have something broken with your WiFi storage. If not, submit an issue to this repository with information. 60 | --- 61 | - ### NetworkManager isn't installed: 62 | - This program ***does not work*** without NetworkManager on Linux. If you want to use this program, install it using your distributions package manager or software center. Not using NetworkManager is a strange decision, but that's an issue for another time. 63 | --- 64 | - ### Have another issue? 65 | - Open a useful issue on this GitHub, and/or suggest a new item in this list if you find a solution. 66 | 67 | --- 68 | --- 69 | ## Reference 70 | - This project is an improvement of [wifi-password](https://github.com/rauchg/wifi-password) created by [@rauchg](https://github.com/rauchg), where I have added support for multiple platforms and have added the feature for generating QR codes. 71 | - [wifiPassword](https://github.com/ankitjain28may/wifiPassword) created by [@ankitjain28may](https://github.com/ankitjain28may) was frequently used as reference throughout the development of this project. 72 | -------------------------------------------------------------------------------- /wifi_password/wifi_password.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Quickly fetch your WiFi password and if needed, generate a QR code 5 | of your WiFi to allow phones to easily connect 6 | 7 | by Siddharth Dushantha 8 | """ 9 | 10 | import pathlib 11 | import sys 12 | import argparse 13 | from shutil import which 14 | import re 15 | import os 16 | 17 | import utils 18 | import constants 19 | 20 | __version__ = "1.1.1" 21 | 22 | def print_error(text) -> None: 23 | """ 24 | Shows an error message and exits the program with the status code 1 25 | """ 26 | print(f"ERROR: {text}", file=sys.stderr) 27 | sys.exit(1) 28 | 29 | def get_ssid() -> str: 30 | """ 31 | Get the SSID which the computer is currently connected to 32 | """ 33 | platform = utils.get_platform() 34 | 35 | if platform == constants.MAC: 36 | airport = pathlib.Path(constants.AIRPORT_PATH) 37 | 38 | if not airport.is_file(): 39 | print_error(f"Can't find 'airport' command at {airport}") 40 | 41 | ssid = utils.run_command(f"{airport} -I | awk '/ SSID/ {{print substr($0, index($0, $2))}}'") 42 | 43 | elif platform == constants.LINUX: 44 | if which("nmcli") is None: 45 | print_error("Network Manager is required to run this program on Linux.") 46 | 47 | ssid = utils.run_command("nmcli -t -f active,ssid dev wifi | egrep '^yes:' | sed 's/^yes://'") 48 | 49 | elif platform == constants.WINDOWS: 50 | ssid = utils.run_command("netsh wlan show interfaces | findstr SSID") 51 | 52 | if ssid == "": 53 | print_error("SSID was not found") 54 | 55 | ssid = re.findall(r"[^B]SSID\s+:\s(.*)", ssid)[0] 56 | 57 | return ssid 58 | 59 | def main() -> None: 60 | parser = argparse.ArgumentParser(usage="%(prog)s [options]") 61 | parser.add_argument("--show-qr", "-show", 62 | action="store_true", 63 | default=False, 64 | help="Show a ASCII QR code onto the terminal/console") 65 | 66 | parser.add_argument("--save-qr", "-save", 67 | metavar="PATH", 68 | nargs="?", 69 | const="STORE_LOCALLY", 70 | help="Create the QR code and save it as an image") 71 | 72 | parser.add_argument("--ssid", "-s", 73 | help="Specify a SSID that you have previously connected to") 74 | 75 | parser.add_argument('--list', "-l", 76 | action="store_true", 77 | default=False, 78 | help="Lists all stored network SSID") 79 | 80 | parser.add_argument("--version", 81 | action="store_true", 82 | help="Show version number") 83 | 84 | args = parser.parse_args() 85 | 86 | if args.version: 87 | print(__version__) 88 | sys.exit() 89 | 90 | wifi_dict = {} 91 | 92 | if args.list: 93 | profiles = utils.get_profiles() 94 | wifi_dict= utils.generate_wifi_dict(profiles) 95 | utils.print_dict(wifi_dict) 96 | return 97 | 98 | if args.ssid is None: 99 | args.ssid = get_ssid() 100 | 101 | ssid = get_ssid() if not args.ssid else args.ssid.split(',') 102 | 103 | if ssid: 104 | wifi_dict = utils.generate_wifi_dict(ssid) 105 | 106 | if args.show_qr or args.save_qr: 107 | for key, value in wifi_dict.items(): 108 | utils.generate_qr_code(ssid=key, password=value, path=args.save_qr, show_qr=args.show_qr) 109 | return 110 | 111 | utils.print_dict(wifi_dict) 112 | 113 | if __name__ == "__main__": 114 | main() -------------------------------------------------------------------------------- /wifi_password/utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import re 5 | import subprocess 6 | import qrcode 7 | import colorama 8 | 9 | import constants 10 | 11 | def get_platform() -> str: 12 | """ 13 | Returns the name of the platform where the application is currently running 14 | """ 15 | platforms = { 16 | 'linux': constants.LINUX, 17 | 'linux1': constants.LINUX, 18 | 'linux2': constants.LINUX, 19 | 'darwin': constants.MAC, 20 | 'win32': constants.WINDOWS 21 | } 22 | 23 | if not sys.platform in platforms: 24 | return sys.platform 25 | 26 | return platforms[sys.platform] 27 | 28 | def get_profiles() -> list: 29 | """ 30 | Gets a list of names from saved wifi networks in the current platform 31 | """ 32 | profiles = [] 33 | 34 | platform = get_platform() 35 | 36 | try: 37 | if platform == constants.MAC: 38 | # Command found here : https://coderwall.com/p/ghl-cg/list-known-wlans 39 | profiles = run_command(f"defaults read ~/Library/Logs/com.apple.wifi.syncable-networks.plist | grep \" SSID\" | sed 's/^.*= \(.*\);$/\\1/' | sed 's/^\"\\(.*\)\"$/\\1/'").split('\n') 40 | elif platform == constants.LINUX: 41 | if os.getuid() != 0: 42 | ssid = run_command(f"sudo ls /etc/NetworkManager/system-connections/ | grep .nmconnection").split('\n') 43 | else: 44 | ssid = run_command(f"ls /etc/NetworkManager/system-connections/ | grep .nmconnection").split('\n') 45 | 46 | for entry in ssid: 47 | profiles.append(entry.split('.nmconnection')[0]) 48 | elif platform == constants.WINDOWS: 49 | # Reference: https://www.geeksforgeeks.org/getting-saved-wifi-passwords-using-python/ 50 | # getting meta data 51 | meta_data = run_command('netsh wlan show profiles | findstr ":"') 52 | 53 | if meta_data != "": 54 | # splitting data line by line 55 | data = meta_data.split('\n') 56 | 57 | if len(data) > 0: 58 | # skip the first element in data since it does not contain a valid profile returned by netsh command 59 | profiles = [d.split(':')[1].strip(' .\r') for d in data[1:]] 60 | except Exception as ex: 61 | print(f'Error: {ex}') 62 | 63 | return profiles 64 | 65 | def generate_wifi_dict(profiles: list) -> dict: 66 | """ 67 | Generates a dictionary with the wifi name as key and the password as it's value 68 | """ 69 | wifi_dict = {} 70 | 71 | if profiles is None: 72 | print(f'List is not defined.') 73 | return 74 | 75 | if len(profiles) == 0: 76 | print(f'List is empty.') 77 | return 78 | 79 | for ssid in profiles: 80 | if get_platform() == constants.MAC and len(profiles) > 1: 81 | password = "*****" 82 | else: 83 | password = get_password(ssid) 84 | 85 | wifi_dict[ssid] = password 86 | 87 | return wifi_dict 88 | 89 | def get_password(ssid: str) -> str: 90 | """ 91 | Gets the password for a given SSID 92 | """ 93 | password = "" 94 | 95 | if ssid == "" or ssid is None: 96 | print("SSID is not defined") 97 | return password 98 | 99 | platform = get_platform() 100 | 101 | try: 102 | if platform == constants.MAC: 103 | password = run_command(f"security find-generic-password -l \"{ssid}\" -D 'AirPort network password' -w") 104 | elif platform == constants.LINUX: 105 | # Check if the user is running with super user privilages 106 | if os.getuid() != 0: 107 | password = run_command(f"sudo nmcli -s -g 802-11-wireless-security.psk connection show '{ssid}'") 108 | else: 109 | password = run_command(f"nmcli -s -g 802-11-wireless-security.psk connection show '{ssid}'") 110 | elif platform == constants.WINDOWS: 111 | password = run_command(f"chcp 437 | netsh wlan show profile name=\"{ssid}\" key=clear | findstr Key") 112 | 113 | if password != "": 114 | password = re.findall(r"Key Content\s+:\s(.*)", password) 115 | 116 | if len(password) > 0: 117 | password = password[0] 118 | else: 119 | password = "" 120 | except Exception as ex: 121 | print(f'Error: {ex}') 122 | 123 | return password 124 | 125 | def run_command(command: str) -> str: 126 | """ 127 | Runs a given command using subprocess module 128 | """ 129 | if command == "" or command is None: 130 | return "" 131 | 132 | env = os.environ.copy() 133 | env["LANG"] = "C" 134 | output, _ = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, shell=True, env=env).communicate() 135 | return output.decode("utf-8", errors="replace").rstrip("\r\n") 136 | 137 | def print_dict(ssid: dict) -> None: 138 | """ 139 | Prints the contents of the given dictionary that contains the wifi name and password 140 | """ 141 | if ssid is None: 142 | print(f'Dictionary is not defined.') 143 | return 144 | 145 | if len(ssid) == 0: 146 | print(f'Dictionary is empty.') 147 | return 148 | 149 | print("----------------------------------------------") 150 | print("{:<30}| {:<}".format("SSID", "Password")) 151 | print("----------------------------------------------") 152 | 153 | for key, value in ssid.items(): 154 | print("{:<30}| {:<}".format(key, value)) 155 | 156 | print("----------------------------------------------") 157 | # If macOS and list 158 | 159 | if get_platform() == constants.MAC and len(ssid) > 1: 160 | print(f"Use 'wifi-password -s ' to find a specific WIFI password") 161 | 162 | def generate_qr_code(ssid: str, password: str, path: str, show_qr: bool) -> None: 163 | """ 164 | Generates a QR code from a given ssid and password 165 | 166 | Source: https://git.io/JtLIv 167 | """ 168 | if ssid == "" or ssid is None: 169 | print('SSID is not specified, cannot generate QR code.') 170 | return 171 | 172 | text = f"WIFI:T:WPA;S:{ssid};P:{password};;" 173 | 174 | try: 175 | qr = qrcode.QRCode(version=1, 176 | error_correction=qrcode.constants.ERROR_CORRECT_L, 177 | box_size=10, 178 | border=4) 179 | qr.add_data(text) 180 | 181 | if show_qr: 182 | print(f'---------- {ssid} ----------') 183 | # This will emulate support for ANSI escape sequences, which is needed 184 | # in order to display the QR code on Windows 185 | colorama.init() 186 | qr.make() 187 | qr.print_tty() 188 | 189 | if path: 190 | file_name = ssid.replace(" ", "_") + ".png" 191 | 192 | if path == "STORE_LOCALLY": 193 | path = file_name 194 | 195 | try: 196 | img = qr.make_image() 197 | img.save(path) 198 | 199 | print(f"QR code has been saved to {path}") 200 | except FileNotFoundError: 201 | print(f"No such file/directory: '{path}'") 202 | except Exception as ex: 203 | print(f'QR Code Error: {ex}') 204 | --------------------------------------------------------------------------------