├── .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 |
--------------------------------------------------------------------------------