mirror of
https://github.com/Stone-Red-Code/HotspotAutoLogin.git
synced 2026-11-01 23:05:40 +01:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
337c84e9a4 | ||
|
|
bcbad5b8f8 | ||
|
|
f55f09079a | ||
|
|
7ec6601554 | ||
|
|
10c3b7f233 | ||
|
|
bbc9be3b93 | ||
|
|
2ff513099f | ||
|
|
54eea0ad63 | ||
|
|
fee77034f4 | ||
|
|
af880b0e92 | ||
|
|
c495415df9 |
@@ -16,8 +16,8 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
- Double-click on HotspotAutoLogin.exe to launch the application.
|
||||
|
||||
### Option 2: Run with Python
|
||||
- Clone or download the repository to your local machine.
|
||||
- Install Python to your computer.
|
||||
- Clone or [download the repository](https://github.com/denizsafak/HotspotAutoLogin/archive/refs/heads/main.zip) to your local machine.
|
||||
- Extract from zip.
|
||||
- Run "run.bat" file.
|
||||
|
||||
## `Features`
|
||||
@@ -32,6 +32,8 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
- You can view the log of the script's actions by clicking the "Show Log" option in the system tray menu.
|
||||
|
||||
## `How to Configure the config.json?`
|
||||
> [!TIP]
|
||||
> I recebtly, added "Add new" button to the program, so you can achieve the same thing without needing to edit the config.json.
|
||||
|
||||

|
||||
|
||||
@@ -46,6 +48,8 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
|
||||
`"url":` Enter the "Request URL" in the "Headers" tab here.
|
||||
|
||||
`"internet_check_url":` URL to check your internet connection. Program will try to access this address to check if you have internet connection. If 8.8.8.8 is accessible **before** you log into your network, change this.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -60,9 +64,10 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
{
|
||||
"profiles": [
|
||||
{
|
||||
"name": "My School Wi-Fi",
|
||||
"ssid": "SCHOOL_WIFI_5G",
|
||||
"name": "Example Wi-Fi",
|
||||
"ssid": "EXAMPLE_WIFI_5G",
|
||||
"url": "https://connect.schoolwifi.com/api/portal/dynamic/authenticate",
|
||||
"internet_check_url": "8.8.8.8",
|
||||
"payload": {
|
||||
"username": "[email protected]",
|
||||
"password": "123455678"
|
||||
@@ -79,9 +84,10 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "My School ETHERNET",
|
||||
"name": "Example ETHERNET",
|
||||
"url": "http://10.3.41.15:8002/index.php?zone=dormnet",
|
||||
"payload": "&auth_user=85795013%40myschool.com&auth_pass=123455678&redirurl=&accept=Login",
|
||||
"internet_check_url": "8.8.8.8",
|
||||
"headers": {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Connection": "keep-alive",
|
||||
@@ -97,6 +103,10 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
> [!CAUTION]
|
||||
> Recent Windows updates restricts third-party apps from accessing Wi-Fi names unless location services are enabled. To fix this, turn on location services in your settings. For more details, check the article from 04/02/2024 [Changes to API behavior for Wi-Fi access and location](https://learn.microsoft.com/en-us/windows/win32/nativewifi/wi-fi-access-location-changes).
|
||||
|
||||
> [!NOTE]
|
||||
> - The script relies on the assumption that the web portal uses basic authentication. If the portal uses a more complex login mechanism, additional adjustments may be necessary.
|
||||
> - This script is primarily intended for Windows. Adaptations might be needed for other operating systems.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 101 KiB |
+466
-54
@@ -3,9 +3,14 @@ import os
|
||||
import requests
|
||||
import time
|
||||
import subprocess
|
||||
import re
|
||||
import socket
|
||||
import pystray
|
||||
import threading
|
||||
import tkinter as tk
|
||||
import tkinter.ttk as ttk
|
||||
import tkinter.messagebox as messagebox
|
||||
from urllib.parse import urlparse
|
||||
from tkinter import Text, Scrollbar
|
||||
from PIL import Image
|
||||
from collections import deque
|
||||
@@ -24,7 +29,7 @@ os.chdir(script_dir)
|
||||
|
||||
# Program Information
|
||||
program_name = "HotspotAutoLogin"
|
||||
version = "v1.83"
|
||||
version = "v1.90"
|
||||
github_link = "https://github.com/denizsafak/HotspotAutoLogin"
|
||||
|
||||
# Function to center a window on the screen
|
||||
@@ -54,12 +59,17 @@ def update_profile_details(event):
|
||||
profile_name.config(text=f"Selected Profile: {selected_profile['name']}")
|
||||
profile_details.config(state=tk.NORMAL)
|
||||
profile_details.delete(1.0, tk.END)
|
||||
# Insert profile details with all variables except "name"WWWW
|
||||
# Insert profile details as JSON with coloring
|
||||
profile_details.tag_configure("bold", font=("Courier New", 10, "bold"), foreground="#08872a")
|
||||
for key, value in selected_profile.items():
|
||||
if key != 'name': # Skip displaying the "name" variable
|
||||
profile_details.insert(tk.END, f"{key}: ", "bold")
|
||||
profile_details.insert(tk.END, f"{value}\n")
|
||||
profile_details.tag_configure("normal", font=("Courier New", 10), foreground="#000000")
|
||||
profile_json = json.dumps({k: v for k, v in selected_profile.items() if k != 'name'}, indent=4)
|
||||
for line in profile_json.splitlines():
|
||||
if ':' in line:
|
||||
key, value = line.split(':', 1)
|
||||
profile_details.insert(tk.END, key + ':', "bold")
|
||||
profile_details.insert(tk.END, value + "\n", "normal")
|
||||
else:
|
||||
profile_details.insert(tk.END, line + "\n", "normal")
|
||||
profile_details.config(state=tk.DISABLED)
|
||||
else:
|
||||
profile_name.config(text="Selected Profile: ")
|
||||
@@ -107,17 +117,380 @@ center_window(root, width, height)
|
||||
# Create a frame for listing profiles
|
||||
profiles_frame = tk.Frame(root)
|
||||
profiles_frame.pack(side=tk.LEFT, fill=tk.Y, padx=10, pady=10)
|
||||
# Create a frame to hold the listbox and its scrollbar
|
||||
listbox_frame = tk.Frame(profiles_frame)
|
||||
listbox_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)
|
||||
# Create a listbox to display available profiles
|
||||
listbox = tk.Listbox(profiles_frame, selectmode=tk.SINGLE)
|
||||
listbox.pack(side=tk.LEFT, fill=tk.Y)
|
||||
listbox = tk.Listbox(listbox_frame, selectmode=tk.SINGLE)
|
||||
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
|
||||
def scan_wifi_ssids():
|
||||
ssids = []
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["netsh", "wlan", "show", "networks"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
shell=True,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW
|
||||
)
|
||||
output = result.stdout
|
||||
for line in output.splitlines():
|
||||
line = line.strip()
|
||||
if line.startswith("SSID"):
|
||||
parts = line.split(" : ")
|
||||
if len(parts) == 2:
|
||||
ssids.append(parts[1])
|
||||
except:
|
||||
pass
|
||||
return ssids
|
||||
|
||||
def add_new_profile():
|
||||
def show_context_menu(event):
|
||||
context_menu = tk.Menu(root, tearoff=0)
|
||||
context_menu.add_command(label="Cut", command=lambda: event.widget.event_generate("<<Cut>>"))
|
||||
context_menu.add_command(label="Copy", command=lambda: event.widget.event_generate("<<Copy>>"))
|
||||
context_menu.add_command(label="Paste", command=lambda: event.widget.event_generate("<<Paste>>"))
|
||||
context_menu.tk_popup(event.x_root, event.y_root)
|
||||
|
||||
def get_current_connected_ssid():
|
||||
try:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
output = subprocess.check_output(["netsh", "wlan", "show", "interfaces"], text=True, startupinfo=startupinfo)
|
||||
match = re.search(r"^\s*SSID\s*:\s*(.+)$", output, re.MULTILINE)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
except subprocess.CalledProcessError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def toggle_ethernet():
|
||||
if use_ethernet_var.get():
|
||||
ssid_combo.config(state="disabled")
|
||||
else:
|
||||
ssid_combo.config(state="normal")
|
||||
|
||||
def refresh_wifi_list():
|
||||
ssid_list = scan_wifi_ssids()
|
||||
ssid_combo["values"] = ssid_list
|
||||
if ssid_list and not use_ethernet_var.get():
|
||||
ssid_var.set(ssid_list[0])
|
||||
|
||||
def error_message(message):
|
||||
if message:
|
||||
error_label.config(text=message, bg="red")
|
||||
if not error_label.winfo_ismapped():
|
||||
error_label.pack(fill="x", pady=(5, 5))
|
||||
add_window.update_idletasks()
|
||||
add_window.geometry(f"{add_window.winfo_width()}x{add_window.winfo_height() + error_label.winfo_reqheight()+10}")
|
||||
else:
|
||||
if error_label.winfo_ismapped():
|
||||
add_window.geometry(f"{add_window.winfo_width()}x{add_window.winfo_height() - error_label.winfo_reqheight()+10}")
|
||||
error_label.pack_forget()
|
||||
|
||||
def save_profile():
|
||||
raw_payload = payload_text.get("1.0", tk.END).rstrip("\n").strip(" ,")
|
||||
raw_headers = headers_text.get("1.0", tk.END).rstrip("\n").strip(" ,")
|
||||
# Validate inputs
|
||||
name = name_var.get().strip()
|
||||
ssid = ssid_var.get().strip()
|
||||
url = url_var.get().strip()
|
||||
internet_check_url = internet_check_url_var.get().strip()
|
||||
check_every_second = check_every_second_var.get().strip()
|
||||
dialog_width = dialog_width_var.get().strip()
|
||||
dialog_height = dialog_height_var.get().strip()
|
||||
|
||||
if not name:
|
||||
error_message("Name cannot be empty.")
|
||||
return
|
||||
if any(profile['name'].strip().lower() == name.lower() for profile in profiles):
|
||||
error_message("Profile with this name already exists.")
|
||||
return
|
||||
if not ssid:
|
||||
error_message("SSID cannot be empty.")
|
||||
return
|
||||
if not url:
|
||||
error_message("Request URL cannot be empty.")
|
||||
return
|
||||
# Check if URL is valid
|
||||
parsed_url = urlparse(url)
|
||||
if not all([parsed_url.scheme, parsed_url.netloc]):
|
||||
error_message("Invalid URL.")
|
||||
return
|
||||
if not raw_payload.strip():
|
||||
error_message("Payload cannot be empty.")
|
||||
return
|
||||
if not internet_check_url:
|
||||
error_message("internet_check_url_var cannot be empty.")
|
||||
return
|
||||
if not check_every_second:
|
||||
error_message("check_every_second cannot be empty.")
|
||||
return
|
||||
if not dialog_width:
|
||||
error_message("dialog_width cannot be empty.")
|
||||
return
|
||||
if not dialog_height:
|
||||
error_message("dialog_height cannot be empty.")
|
||||
return
|
||||
|
||||
try:
|
||||
parsed_headers = json.loads(raw_headers)
|
||||
except json.JSONDecodeError:
|
||||
error_message("Headers must be valid JSON.")
|
||||
return
|
||||
|
||||
if len(raw_payload.splitlines()) == 1:
|
||||
parsed_payload = raw_payload
|
||||
else:
|
||||
try:
|
||||
parsed_payload = json.loads(raw_payload)
|
||||
except json.JSONDecodeError:
|
||||
error_message("Payload must be valid JSON.")
|
||||
return
|
||||
|
||||
# Hide error message if any
|
||||
error_message("")
|
||||
new_profile = {
|
||||
"name": name,
|
||||
"url": url,
|
||||
"internet_check_url": internet_check_url,
|
||||
"payload": parsed_payload,
|
||||
"headers": parsed_headers,
|
||||
"check_every_second": int(check_every_second),
|
||||
"dialog_geometry": {"width": int(dialog_width), "height": int(dialog_height)}
|
||||
}
|
||||
if not use_ethernet_var.get():
|
||||
new_profile["ssid"] = ssid
|
||||
profiles.append(new_profile)
|
||||
config["profiles"] = profiles
|
||||
with open("config.json", "w") as f:
|
||||
json.dump(config, f, indent=2)
|
||||
listbox.insert(tk.END, name)
|
||||
add_window.destroy()
|
||||
|
||||
def cancel():
|
||||
add_window.destroy()
|
||||
add_window = tk.Toplevel(root)
|
||||
add_window.title("Add New Profile")
|
||||
container = tk.Frame(add_window, padx=10, pady=5)
|
||||
container.pack(fill="both", expand=True)
|
||||
wifi_ssids = scan_wifi_ssids()
|
||||
connected_ssid = get_current_connected_ssid()
|
||||
if not connected_ssid and wifi_ssids:
|
||||
connected_ssid = wifi_ssids[0]
|
||||
if not connected_ssid:
|
||||
connected_ssid = "Enter SSID"
|
||||
|
||||
def generate_unique_name():
|
||||
base_name = "New profile"
|
||||
existing_names = [profile['name'].strip().lower() for profile in profiles]
|
||||
if base_name.lower() not in existing_names:
|
||||
return base_name
|
||||
i = 2
|
||||
while f"{base_name} {i}".lower() in existing_names:
|
||||
i += 1
|
||||
return f"{base_name} {i}"
|
||||
|
||||
name_var = tk.StringVar(value=generate_unique_name())
|
||||
ssid_var = tk.StringVar(value=connected_ssid)
|
||||
url_var = tk.StringVar()
|
||||
internet_check_url_var = tk.StringVar(value="8.8.8.8")
|
||||
check_every_second_var = tk.StringVar(value="600")
|
||||
dialog_width_var = tk.StringVar(value="1024")
|
||||
dialog_height_var = tk.StringVar(value="500")
|
||||
use_ethernet_var = tk.BooleanVar(value=False)
|
||||
# Name
|
||||
name_frame = tk.Frame(container)
|
||||
name_frame.pack(fill="x", pady=5)
|
||||
tk.Label(name_frame, text="Name:").pack(side="left")
|
||||
name_entry = tk.Entry(name_frame, textvariable=name_var)
|
||||
name_entry.pack(side="left", fill="x", expand=True)
|
||||
name_entry.bind("<Button-3>", show_context_menu)
|
||||
# SSID row
|
||||
ssid_frame = tk.Frame(container)
|
||||
ssid_frame.pack(fill="x", pady=5)
|
||||
tk.Label(ssid_frame, text="SSID:").pack(side="left")
|
||||
ssid_combo = ttk.Combobox(ssid_frame, textvariable=ssid_var, values=wifi_ssids)
|
||||
ssid_combo.pack(side="left", fill="x", expand=True)
|
||||
ssid_combo.bind("<Button-3>", show_context_menu)
|
||||
tk.Button(ssid_frame, text="Refresh", command=refresh_wifi_list).pack(side="left", padx=5)
|
||||
ethernet_chk = tk.Checkbutton(ssid_frame, text="Ethernet", variable=use_ethernet_var, command=toggle_ethernet)
|
||||
ethernet_chk.pack(side="left", padx=5)
|
||||
# URL
|
||||
url_frame = tk.Frame(container)
|
||||
url_frame.pack(fill="x", pady=5)
|
||||
tk.Label(url_frame, text="Request URL:").pack(side="left")
|
||||
url_entry = tk.Entry(url_frame, textvariable=url_var)
|
||||
url_entry.pack(side="left", fill="x", expand=True)
|
||||
url_entry.bind("<Button-3>", show_context_menu)
|
||||
# internet_check_url
|
||||
internet_frame = tk.Frame(container)
|
||||
internet_frame.pack(fill="x", pady=5)
|
||||
tk.Label(internet_frame, text="internet_check_url:").pack(side="left")
|
||||
internet_entry = tk.Entry(internet_frame, textvariable=internet_check_url_var)
|
||||
internet_entry.pack(side="left", fill="x", expand=True)
|
||||
internet_entry.bind("<Button-3>", show_context_menu)
|
||||
# payload
|
||||
tk.Label(container, text="payload:").pack(anchor="w")
|
||||
payload_frame = tk.Frame(container)
|
||||
payload_frame.pack(fill="both", pady=5, expand=True)
|
||||
payload_text = tk.Text(payload_frame, height=8)
|
||||
payload_text.pack(side="left", fill="both", expand=True)
|
||||
payload_text.bind("<Button-3>", show_context_menu)
|
||||
payload_scroll = tk.Scrollbar(payload_frame, command=payload_text.yview)
|
||||
payload_scroll.pack(side="right", fill="y")
|
||||
payload_text.config(yscrollcommand=payload_scroll.set)
|
||||
# headers
|
||||
tk.Label(container, text="headers:").pack(anchor="w")
|
||||
headers_frame = tk.Frame(container)
|
||||
headers_frame.pack(fill="both", pady=5, expand=True)
|
||||
headers_text = tk.Text(headers_frame, height=8)
|
||||
headers_text.pack(side="left", fill="both", expand=True)
|
||||
headers_text.bind("<Button-3>", show_context_menu)
|
||||
headers_scroll = tk.Scrollbar(headers_frame, command=headers_text.yview)
|
||||
headers_scroll.pack(side="right", fill="y")
|
||||
headers_text.config(yscrollcommand=headers_scroll.set)
|
||||
headers_text.insert(tk.END, """{
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Connection": "keep-alive",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
|
||||
}""")
|
||||
# check_every_second
|
||||
check_frame = tk.Frame(container)
|
||||
check_frame.pack(fill="x", pady=5)
|
||||
tk.Label(check_frame, text="check_every_second:").pack(side="left")
|
||||
check_entry = tk.Entry(check_frame, textvariable=check_every_second_var)
|
||||
check_entry.pack(side="left", fill="x", expand=True)
|
||||
check_entry.bind("<Button-3>", show_context_menu)
|
||||
# dialog_geometry width and height
|
||||
dialog_geometry_frame = tk.Frame(container)
|
||||
dialog_geometry_frame.pack(fill="x", pady=5)
|
||||
tk.Label(dialog_geometry_frame, text="dialog_geometry:").pack(side="left")
|
||||
tk.Label(dialog_geometry_frame, text="width:").pack(side="left", padx=(0, 0))
|
||||
dialog_width_entry = tk.Entry(dialog_geometry_frame, textvariable=dialog_width_var, width=5)
|
||||
dialog_width_entry.pack(side="left")
|
||||
dialog_width_entry.bind("<Button-3>", show_context_menu)
|
||||
tk.Label(dialog_geometry_frame, text="height:").pack(side="left", padx=(5, 0))
|
||||
dialog_height_entry = tk.Entry(dialog_geometry_frame, textvariable=dialog_height_var, width=5)
|
||||
dialog_height_entry.pack(side="left")
|
||||
dialog_height_entry.bind("<Button-3>", show_context_menu)
|
||||
# Buttons
|
||||
button_frame = tk.Frame(container)
|
||||
button_frame.pack(fill="x", pady=5)
|
||||
cancel_button = tk.Button(
|
||||
button_frame,
|
||||
text="Cancel",
|
||||
command=cancel,
|
||||
padx=20,
|
||||
pady=5,
|
||||
fg="white",
|
||||
bg="grey",
|
||||
activebackground="#606060",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
cancel_button.pack(side=tk.LEFT, fill="x", padx=(0, 2), pady=(10, 0), expand=False)
|
||||
save_button = tk.Button(
|
||||
button_frame,
|
||||
text="Add",
|
||||
command=save_profile,
|
||||
padx=5,
|
||||
pady=5,
|
||||
fg="white",
|
||||
bg="#08872a",
|
||||
activebackground="#076921",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
save_button.pack(side=tk.LEFT, fill="x", padx=(2, 0), pady=(10, 0), expand=True)
|
||||
# Error message
|
||||
error_label = tk.Label(container, text="", bg="red", fg="white")
|
||||
# Make the window resizable
|
||||
add_window.columnconfigure(0, weight=1)
|
||||
add_window.rowconfigure(0, weight=1)
|
||||
container.columnconfigure(0, weight=1)
|
||||
container.rowconfigure(0, weight=1)
|
||||
# Configure resizing for frames and text widgets
|
||||
name_frame.columnconfigure(1, weight=1)
|
||||
ssid_frame.columnconfigure(1, weight=1)
|
||||
url_frame.columnconfigure(1, weight=1)
|
||||
internet_frame.columnconfigure(1, weight=1)
|
||||
payload_frame.columnconfigure(0, weight=1)
|
||||
headers_frame.columnconfigure(0, weight=1)
|
||||
check_frame.columnconfigure(1, weight=1)
|
||||
dialog_geometry_frame.columnconfigure(1, weight=1)
|
||||
button_frame.columnconfigure(1, weight=1)
|
||||
# Calculate and set the minimum height based on the current height of the items
|
||||
add_window.update_idletasks()
|
||||
min_height = add_window.winfo_height()
|
||||
default_width = 400
|
||||
add_window.geometry(f"{default_width}x{min_height}")
|
||||
add_window.minsize(default_width, min_height)
|
||||
# Center the add_window on the root window
|
||||
root.update_idletasks()
|
||||
x = root.winfo_x() + (root.winfo_width() // 2) - (default_width // 2)
|
||||
y = root.winfo_y() + (root.winfo_height() // 2) - (min_height // 2)
|
||||
add_window.geometry(f"+{x}+{y}")
|
||||
|
||||
def remove_selected_profile():
|
||||
selected_index = listbox.curselection()
|
||||
if not selected_index:
|
||||
return
|
||||
selected_index = selected_index[0]
|
||||
selected_profile = profiles[selected_index]
|
||||
if messagebox.askyesno("Confirm Delete", f"Are you sure you want to delete the profile '{selected_profile['name']}'?"):
|
||||
profiles.pop(selected_index)
|
||||
config["profiles"] = profiles
|
||||
with open("config.json", "w") as f:
|
||||
json.dump(config, f, indent=2)
|
||||
listbox.delete(selected_index)
|
||||
profile_details.config(state=tk.NORMAL)
|
||||
profile_details.delete("1.0", tk.END)
|
||||
profile_details.config(state=tk.DISABLED)
|
||||
profile_name.config(text="Selected Profile: ")
|
||||
|
||||
# Add buttons under the listbox
|
||||
button_frame = tk.Frame(profiles_frame)
|
||||
button_frame.pack(side=tk.LEFT, pady=(0,5))
|
||||
|
||||
add_button = tk.Button(
|
||||
button_frame,
|
||||
text="Add new",
|
||||
command=add_new_profile,
|
||||
padx=5,
|
||||
pady=0,
|
||||
fg="white",
|
||||
bg="#08872a",
|
||||
activebackground="#076921",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
add_button.pack(side=tk.LEFT, padx=(0,5))
|
||||
|
||||
remove_button = tk.Button(
|
||||
button_frame,
|
||||
text="Remove",
|
||||
command=remove_selected_profile,
|
||||
padx=5,
|
||||
pady=0,
|
||||
fg="white",
|
||||
bg="grey",
|
||||
activebackground="#606060",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
remove_button.pack(side=tk.LEFT, padx=0)
|
||||
for profile in profiles:
|
||||
listbox.insert(tk.END, profile['name'])
|
||||
|
||||
listbox.bind('<Delete>', lambda event: remove_selected_profile())
|
||||
# Create a vertical scrollbar for the listbox
|
||||
scrollbar = tk.Scrollbar(profiles_frame, orient=tk.VERTICAL)
|
||||
scrollbar = tk.Scrollbar(listbox_frame, orient=tk.VERTICAL)
|
||||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
# Link the listbox and scrollbar
|
||||
listbox.config(yscrollcommand=scrollbar.set)
|
||||
scrollbar.config(command=listbox.yview)
|
||||
# Bind the listbox selection event to update and refresh the profile details
|
||||
@@ -140,7 +513,6 @@ profile_scrollbar = Scrollbar(profile_details, command=profile_details.yview)
|
||||
profile_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
|
||||
# Link the profile details Text widget and scrollbar
|
||||
profile_details.config(yscrollcommand=profile_scrollbar.set)
|
||||
|
||||
# Function to exit the application
|
||||
def on_closing():
|
||||
root.destroy()
|
||||
@@ -253,13 +625,29 @@ def send_request():
|
||||
# Function to check if internet is available
|
||||
def is_internet_available():
|
||||
try:
|
||||
# -n is the number of pings
|
||||
# -l is the size of the packet
|
||||
# -w is the timeout in seconds
|
||||
subprocess.run(['ping', internet_check_url, '-n', '3', '-l', '32', '-w', '20'], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
internet_check_url_clean = internet_check_url.replace("http://", "").replace("https://", "")
|
||||
socket.setdefaulttimeout(3)
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
if internet_check_url_clean.replace('.', '').isdigit():
|
||||
address = internet_check_url_clean
|
||||
else:
|
||||
try:
|
||||
address = socket.gethostbyname(internet_check_url_clean)
|
||||
except socket.gaierror:
|
||||
return False
|
||||
if internet_check_url.startswith("https://"):
|
||||
port = 443
|
||||
elif internet_check_url.startswith("http://"):
|
||||
port = 80
|
||||
else:
|
||||
port = 53
|
||||
server_address = (address, port)
|
||||
s.connect(server_address)
|
||||
except OSError as error:
|
||||
return False
|
||||
finally:
|
||||
s.close()
|
||||
return True
|
||||
|
||||
# Function to get the currently connected SSID using system commands (for Windows)
|
||||
def get_connected_network():
|
||||
@@ -274,17 +662,20 @@ def get_connected_network():
|
||||
if "Ethernet" in line:
|
||||
return "Ethernet"
|
||||
# If not connected to Ethernet, check Wi-Fi SSID
|
||||
wifi_output = subprocess.check_output(["netsh", "wlan", "show", "interfaces"], startupinfo=startupinfo).decode("utf-8")
|
||||
wifi_lines = wifi_output.split("\n")
|
||||
wifi_ssid = None
|
||||
for line in wifi_lines:
|
||||
if "SSID" in line:
|
||||
wifi_ssid = line.strip().split(": ")[1]
|
||||
break
|
||||
if wifi_ssid is not None:
|
||||
return wifi_ssid
|
||||
else:
|
||||
return False
|
||||
try:
|
||||
wifi_output = subprocess.check_output(["netsh", "wlan", "show", "interfaces"], startupinfo=startupinfo).decode("utf-8")
|
||||
wifi_lines = wifi_output.split("\n")
|
||||
wifi_ssid = None
|
||||
for line in wifi_lines:
|
||||
if "SSID" in line:
|
||||
wifi_ssid = line.strip().split(": ")[1]
|
||||
break
|
||||
if wifi_ssid is not None:
|
||||
return wifi_ssid
|
||||
else:
|
||||
return False
|
||||
except subprocess.CalledProcessError as e:
|
||||
return "Error: " + str(e)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
@@ -346,6 +737,11 @@ def show_log_dialog():
|
||||
# Create label for successful logins count
|
||||
successful_logins_label = tk.Label(log_dialog, text=f"Successful Logins: {successful_logins_count}", anchor="w", padx=5)
|
||||
successful_logins_label.place(x=0, rely=1.0, anchor=tk.SW, bordermode=tk.OUTSIDE)
|
||||
# Define tags for different styles
|
||||
log_text.tag_configure("green", foreground="green")
|
||||
log_text.tag_configure("red", foreground="red")
|
||||
log_text.tag_configure("bold_green", foreground="green", font=("Courier New", 10, "bold"))
|
||||
log_text.tag_configure("bold_red", foreground="red", font=("Courier New", 10, "bold"))
|
||||
update_log()
|
||||
log_dialog.protocol("WM_DELETE_WINDOW", hide_log_dialog)
|
||||
center_window(log_dialog, width, height)
|
||||
@@ -380,19 +776,22 @@ successful_logins_count = 0
|
||||
successful_logins_label = None
|
||||
|
||||
# Function to add a message to the log
|
||||
def add_to_log(message):
|
||||
def add_to_log(message, style=None):
|
||||
global log_messages, successful_logins_count
|
||||
now = datetime.now()
|
||||
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_messages.append(f"({timestamp}) {message}")
|
||||
log_messages.append((f"({timestamp}) {message}", style))
|
||||
update_log() # Update the log window
|
||||
|
||||
# Function to update the log
|
||||
def update_log():
|
||||
if log_text:
|
||||
log_text.delete(1.0, tk.END)
|
||||
for message in get_last_log_messages():
|
||||
log_text.insert(tk.END, message + "\n")
|
||||
for message, style in get_last_log_messages():
|
||||
if style:
|
||||
log_text.insert(tk.END, message + "\n", style)
|
||||
else:
|
||||
log_text.insert(tk.END, message + "\n")
|
||||
update_successful_logins_count() # Update the successful logins count
|
||||
|
||||
# Function to update the successful logins count label
|
||||
@@ -408,8 +807,8 @@ def save_to_file(message):
|
||||
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
# Format the message with the timestamp
|
||||
formatted_message = f"({timestamp}) {message}\n"
|
||||
# Open the file in append mode and write the formatted message
|
||||
with open("log.txt", "a") as f:
|
||||
# Open the file in append mode and write the formatted message with utf-8 encoding
|
||||
with open("log.txt", "a", encoding="utf-8") as f:
|
||||
f.write(formatted_message)
|
||||
|
||||
# Create the system tray icon
|
||||
@@ -433,6 +832,13 @@ def check_network_status():
|
||||
global running, errorcount, sleepcount, connected_ssid_lower, ssid, response, request_success, request_errorcount, successful_logins_count
|
||||
while running and errorcount < 10:
|
||||
connected_ssid = get_connected_network()
|
||||
if isinstance(connected_ssid, str) and "error" in connected_ssid.lower():
|
||||
sleepcount = 60
|
||||
message = "{}\nFailed to get SSID. If location services are disabled, please enable them. Retrying in {} seconds...".format(connected_ssid, str(sleepcount))
|
||||
add_to_log(message, "bold_red")
|
||||
errorcount += 1
|
||||
time.sleep(sleepcount)
|
||||
continue
|
||||
if (connected_ssid):
|
||||
connected_ssid_lower = connected_ssid.lower()
|
||||
if (connected_ssid) and ((connected_ssid_lower == expected_ssid_lower)):
|
||||
@@ -449,13 +855,13 @@ def check_network_status():
|
||||
request_errorcount = 0
|
||||
message = "Connected to {} and internet connection is available. Checking again in {} seconds...".format(connected_ssid, str(sleepcount))
|
||||
errorcount = 0
|
||||
add_to_log(message)
|
||||
add_to_log(message, "bold_green")
|
||||
elif request_success and request_errorcount < 3:
|
||||
# If the request was successful but there is still no internet connection, wait for a few seconds and try again
|
||||
sleepcount = 60
|
||||
request_errorcount += 1
|
||||
message = "Even the request was successful, there is still no internet connection. There might be a problem with your network. If you are using a VPN, please check your VPN connection. Giving it some time and checking again in {} seconds... (Request Again: {}/3)".format(str(sleepcount), str(request_errorcount))
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
else:
|
||||
sleepcount = 5
|
||||
@@ -473,7 +879,7 @@ def check_network_status():
|
||||
request_errorcount = 0
|
||||
successful_logins_count += 1
|
||||
message = "Request was successful. Checking the internet connection in {} seconds...".format(str(sleepcount))
|
||||
add_to_log(message)
|
||||
add_to_log(message, "green")
|
||||
save_to_file(message)
|
||||
except requests.exceptions.RequestException as e:
|
||||
errorcount += 1
|
||||
@@ -491,10 +897,10 @@ def check_network_status():
|
||||
elif status_code == 503:
|
||||
message = "Request failed with 503 Service Unavailable error. Trying to reconnect to the network... (Errors: {}/10)".format(errorcount)
|
||||
else:
|
||||
message = "Request failed with HTTP error ({}). Trying to reconnect to the network... (Errors: {}/10)".format(status_code, errorcount)
|
||||
message = "Request failed with HTTP error ({}). \nTrying to reconnect to the network... (Errors: {}/10)".format(status_code, errorcount)
|
||||
else:
|
||||
message = "Request failed with error: {}. If you are usşng a VPN, please disable it for now. Trying to reconnect to the network... (Errors: {}/10)".format(e, errorcount)
|
||||
add_to_log(message)
|
||||
message = "Request failed with error: {}.\nIf you are using a VPN, please disable it for now. Trying to reconnect to the network... (Errors: {}/10)".format(e, errorcount)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
time.sleep(sleepcount)
|
||||
# If the payload URL is not reachable, try to reconnect to the network
|
||||
@@ -512,7 +918,7 @@ def check_network_status():
|
||||
except Exception as e:
|
||||
errorcount += 1
|
||||
message = "Failed to reconnect to Ethernet: {} (Errors: {}/10)".format(e, errorcount)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
else:
|
||||
try:
|
||||
@@ -525,12 +931,12 @@ def check_network_status():
|
||||
time.sleep(5)
|
||||
subprocess.check_output(['netsh', 'wlan', 'connect', 'name=' + ssid], startupinfo=startupinfo).decode("utf-8")
|
||||
message = "Connected to {}. Running the script again...".format(ssid)
|
||||
add_to_log(message)
|
||||
add_to_log(message ,"green")
|
||||
time.sleep(8)
|
||||
except Exception as e:
|
||||
errorcount += 1
|
||||
message = "Failed to reconnect to {}: {} (Errors: {}/10)".format(ssid, e, errorcount)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
continue
|
||||
else:
|
||||
@@ -548,12 +954,12 @@ def check_network_status():
|
||||
sleepcount = 30
|
||||
message = "If you want to connect to {}, please unplug your ethernet cable or disconnect from {}. Checking again in {} seconds...".format(expected_ssid, connected_ssid, str(sleepcount))
|
||||
errorcount = 0
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
elif expected_ssid == "Ethernet":
|
||||
sleepcount = 30
|
||||
message = "Looks like your ethernet cable is not plugged in. Please plug in your ethernet cable. Checking again in {} seconds...".format(str(sleepcount))
|
||||
errorcount = 0
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
elif wifi_enabled:
|
||||
if (connected_ssid):
|
||||
sleepcount = 10
|
||||
@@ -562,19 +968,25 @@ def check_network_status():
|
||||
else:
|
||||
sleepcount = 10
|
||||
message = "You are not connected to {}. Trying to connect {}...".format(expected_ssid, expected_ssid)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
try:
|
||||
result = subprocess.run(['netsh', 'wlan', 'connect', 'name=' + expected_ssid], capture_output=True, text=True, startupinfo=startupinfo)
|
||||
result = subprocess.run(
|
||||
['netsh', 'wlan', 'connect', 'name=' + expected_ssid],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
startupinfo=startupinfo,
|
||||
creationflags=subprocess.CREATE_NO_WINDOW
|
||||
)
|
||||
if result.returncode != 0:
|
||||
if result.returncode == 1:
|
||||
sleepcount = 20
|
||||
message = "Could not find a Wi-Fi network with SSID: {}. If your Wi-Fi is disabled, please enable it. Checking again in {} seconds...".format(expected_ssid, str(sleepcount))
|
||||
add_to_log(message)
|
||||
add_to_log(message ,"red")
|
||||
else:
|
||||
raise subprocess.CalledProcessError(result.returncode, result.args, result.stderr)
|
||||
else:
|
||||
message = "Connected to {}. Running the script again in {} seconds...".format(expected_ssid, str(sleepcount))
|
||||
add_to_log(message)
|
||||
add_to_log(message, "green")
|
||||
except (subprocess.CalledProcessError, ValueError) as e:
|
||||
errorcount += 1
|
||||
sleepcount = 15
|
||||
@@ -582,23 +994,23 @@ def check_network_status():
|
||||
message = "Failed to connect to {}: {}. Trying again in {} seconds... (Errors:{}/10)".format(expected_ssid, e, str(sleepcount), errorcount)
|
||||
else:
|
||||
message = str(e) + ". Trying again in {} seconds... (Errors:{}/10)".format(str(sleepcount), errorcount)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
elif wifi_enabled == False:
|
||||
sleepcount = 30
|
||||
errorcount += 1
|
||||
message = "You are not connected to Ethernet and your Wi-Fi is disabled. Please enable your Wi-Fi or plug in your ethernet cable. Checking again in {} seconds... (Errors: {}/10)".format(str(sleepcount), errorcount)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
save_to_file(message)
|
||||
else:
|
||||
sleepcount = 30
|
||||
errorcount += 1
|
||||
message = "Something went wrong. Please check your Wi-Fi or Ethernet connection. Checking again in {} seconds... (Errors: {}/10)".format(str(sleepcount), errorcount)
|
||||
save_to_file(message)
|
||||
add_to_log(message)
|
||||
add_to_log(message, "red")
|
||||
time.sleep(sleepcount) # Sleep ... seconds before trying again
|
||||
message = "Maximum error count reached. Exiting in 5 seconds..."
|
||||
add_to_log(message)
|
||||
add_to_log(message, "bold_red")
|
||||
save_to_file(message)
|
||||
time.sleep(5)
|
||||
running = False
|
||||
|
||||
+9
-9
@@ -1,13 +1,13 @@
|
||||
{
|
||||
"profiles": [
|
||||
{
|
||||
"name": "NAME_OF_YOUR_PROFILE (WI-FI EXAMPLE)",
|
||||
"ssid": "SSID_OF_YOUR_WIFI",
|
||||
"url": "PAYLOAD_URL_HERE",
|
||||
"name": "Example Wi-Fi",
|
||||
"ssid": "EXAMPLE_WIFI_5G",
|
||||
"url": "https://connect.schoolwifi.com/api/portal/dynamic/authenticate",
|
||||
"internet_check_url": "8.8.8.8",
|
||||
"payload": {
|
||||
"username": "PLEASE WRITE YOUR OWN PAYLOAD VALUES HERE. THIS IS AN EXAMPLE",
|
||||
"password": "PLEASE WRITE YOUR OWN PAYLOAD VALUES HERE. THIS IS AN EXAMPLE"
|
||||
"username": "[email protected]",
|
||||
"password": "123455678"
|
||||
},
|
||||
"headers": {
|
||||
"Content-Type": "application/json;charset=UTF-8",
|
||||
@@ -21,10 +21,10 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "NAME_OF_YOUR_PROFILE (ETHERNET EXAMPLE)",
|
||||
"url": "PAYLOAD_URL_HERE",
|
||||
"name": "Example ETHERNET",
|
||||
"url": "http://10.3.41.15:8002/index.php?zone=dormnet",
|
||||
"payload": "&auth_user=85795013%40myschool.com&auth_pass=123455678&redirurl=&accept=Login",
|
||||
"internet_check_url": "8.8.8.8",
|
||||
"payload": "&auth_user=XXXX%40gmail.com&auth_pass=xxx&redirurl=&accept=Login",
|
||||
"headers": {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Connection": "keep-alive",
|
||||
@@ -37,4 +37,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user