Compare commits

...
Author SHA1 Message Date
Deniz Şafak 337c84e9a4 v1.90fix3 2025-01-01 18:56:54 +03:00
Deniz Şafak bcbad5b8f8 Update README.md 2025-01-01 04:02:31 +03:00
Deniz Şafak f55f09079a v1.90 2025-01-01 04:00:39 +03:00
Deniz Şafak 7ec6601554 v1.90fix2 2025-01-01 03:45:45 +03:00
Deniz Şafak 10c3b7f233 Add files via upload 2025-01-01 03:45:22 +03:00
Deniz Şafak bbc9be3b93 v.190fix 2025-01-01 03:39:27 +03:00
Deniz Şafak 2ff513099f v1.90 2025-01-01 03:11:00 +03:00
Deniz Şafak 54eea0ad63 Update README.md 2024-10-26 01:07:10 +03:00
Deniz Şafak fee77034f4 Update README.md 2024-10-26 01:06:56 +03:00
Deniz Şafak af880b0e92 Update README.md 2024-10-26 00:57:16 +03:00
Deniz Şafak c495415df9 v1.83 2024-10-26 00:48:35 +03:00
Deniz Şafak 10436f0b4f v1.83 2024-10-26 00:19:34 +03:00
Deniz Şafak 95e62523f4 v1.83 2024-10-25 23:52:59 +03:00
Deniz Şafak 05471f19ac v1.83 2024-10-25 23:52:43 +03:00
Deniz Şafak dcf2b5426f v1.83 2024-10-25 23:52:08 +03:00
Deniz Şafak 79f792f0b0 Update README.md 2024-08-23 18:15:18 +03:00
Deniz Şafak 1f0b3d7de1 Add files via upload 2024-07-22 23:11:58 +03:00
Deniz Şafak c7fec03add Update run.bat 2024-07-22 23:11:18 +03:00
Deniz Şafak cb6c8d5ffd Add files via upload 2024-07-22 11:23:48 +03:00
Deniz Şafak 638e888e83 Delete HotspotAutoLogin.pyw 2024-07-22 11:10:05 +03:00
Deniz Şafak ff2ac683bf Delete requirements.txt 2024-07-22 11:09:52 +03:00
Deniz Şafak 585d8d11d7 Delete log.txt 2024-07-22 11:09:45 +03:00
Deniz Şafak ed01a946b6 Delete icon.ico 2024-07-22 11:09:36 +03:00
Deniz Şafak 224e5625a7 Delete config.json 2024-07-22 11:09:27 +03:00
Deniz Şafak 37fc8a6a76 Delete main/last_known_directory.txt 2024-07-22 11:09:06 +03:00
Deniz Şafak 9d511650f6 v1.82 2024-07-22 11:08:46 +03:00
Deniz Şafak bad72f479a Add files via upload 2024-03-31 22:27:42 +03:00
Deniz Şafak 55bfb8c07d Add files via upload 2024-03-31 18:39:04 +03:00
Deniz Şafak dd966d353d Add files via upload 2024-03-31 18:15:28 +03:00
10 changed files with 1015 additions and 131 deletions
+16 -6
View File
@@ -13,11 +13,11 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
### Option 1: Executable Script
- If you don't want to install Python, you can download the precompiled executable version from the Releases section.
[Download the Latest Executable (.exe) Release](https://github.com/denizsafak/HotspotAutoLogin/releases/latest)
- Double-click on HotspotAutoLogin.exe to launch the application. The wallpaper information display will appear on your screen.
- 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.
![How to Animation.](/examples/howto.gif)
@@ -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.
![Example Request.](/examples/Request.png)
@@ -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

View File
@@ -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
@@ -16,9 +21,15 @@ dns.resolver.default_resolver = dns.resolver.Resolver()
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
################################# REMOVE THIS BEFORE USING PYINSTALLER #################################
# Change the current working directory to the script's directory
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)
################################# REMOVE THIS BEFORE USING PYINSTALLER #################################
# Program Information
program_name = "HotspotAutoLogin"
version = "v1.80"
version = "v1.90"
github_link = "https://github.com/denizsafak/HotspotAutoLogin"
# Function to center a window on the screen
@@ -48,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: ")
@@ -101,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
@@ -134,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()
@@ -223,6 +601,7 @@ root.mainloop()
if selected_profile:
payload = selected_profile.get('payload')
url = selected_profile.get('url', "")
internet_check_url = selected_profile.get('internet_check_url', "")
ssid = selected_profile.get('ssid', "")
check_every_second = selected_profile.get('check_every_second', "")
dialog_geometry = selected_profile.get('dialog_geometry', "")
@@ -246,20 +625,35 @@ 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', '8.8.8.8', '-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():
try:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# Check if connected to Ethernet
ethernet_output = subprocess.check_output(["netsh", "interface", "show", "interface"], startupinfo=startupinfo).decode("utf-8")
ethernet_lines = ethernet_output.split("\n")
@@ -267,17 +661,34 @@ def get_connected_network():
if "Connected" in line:
if "Ethernet" in line:
return "Ethernet"
# If not connected to Ethernet, check Wi-Fi SSID
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
# Is connected to wifi
def is_connected_to_wifi():
try:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
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
return True
else:
return False
except subprocess.CalledProcessError:
@@ -326,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)
@@ -360,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
@@ -388,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
@@ -413,22 +832,36 @@ 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)):
if is_connected_to_wifi() and (connected_ssid == "Ethernet" and expected_ssid == "Ethernet"):
message = "You are both connected to Wi-Fi and Ethernet. Disconnecting from Wi-Fi and continuing with Ethernet..."
add_to_log(message)
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.check_output(['netsh', 'wlan', 'disconnect', 'interface=' + "Wi-Fi"], startupinfo=startupinfo).decode("utf-8")
time.sleep(5)
if (is_internet_available()):
sleepcount = check_every_second
request_success = False
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
@@ -446,11 +879,11 @@ 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
sleepcount = 1
sleepcount = 3
request_success = False
if isinstance(e, requests.exceptions.HTTPError):
# Handle HTTP errors with different messages for different status codes
@@ -464,15 +897,13 @@ 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. Sometimes 'Kill Switch' feature cause this error. 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
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
if connected_ssid == "Ethernet":
try:
# Disable and enable the Ethernet adapter
@@ -487,23 +918,25 @@ 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:
# Disconnect and reconnect to the Wi-Fi network
message = "Disconnecting from {}...".format(ssid)
add_to_log(message)
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.check_output(['netsh', 'wlan', 'disconnect', 'interface=' + "Wi-Fi"], startupinfo=startupinfo).decode("utf-8")
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:
@@ -518,10 +951,15 @@ def check_network_status():
wifi_enabled = True
break
if connected_ssid == "Ethernet":
sleepcount = 60
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, "red")
elif wifi_enabled:
if (connected_ssid):
sleepcount = 10
@@ -530,17 +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 = 60
raise ValueError("Could not find a Wi-Fi network with SSID: {}. Checking again in {} seconds...".format(expected_ssid, str(sleepcount)))
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 ,"red")
else:
raise subprocess.CalledProcessError(result.returncode, result.args, result.stderr)
message = "Connected to {}. Running the script again in {} seconds...".format(expected_ssid, str(sleepcount))
add_to_log(message)
else:
message = "Connected to {}. Running the script again in {} seconds...".format(expected_ssid, str(sleepcount))
add_to_log(message, "green")
except (subprocess.CalledProcessError, ValueError) as e:
errorcount += 1
sleepcount = 15
@@ -548,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
+11 -9
View File
@@ -1,12 +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",
@@ -20,9 +21,10 @@
}
},
{
"name": "NAME_OF_YOUR_PROFILE (ETHERNET EXAMPLE)",
"url": "PAYLOAD_URL_HERE",
"payload": "&auth_user=XXXX%40gmail.com&auth_pass=xxx&redirurl=&accept=Login",
"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",
@@ -35,4 +37,4 @@
}
}
]
}
}
View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

+359
View File
@@ -0,0 +1,359 @@
<!-- : Begin batch script
@echo off
REM PUSHD "%~dp0"
REM author: Badr Elmers 2021-2023
REM description: refrenv = refresh environment. this is a better alternative to the chocolatey refreshenv for cmd
REM version: 1.0
REM https://github.com/badrelmers/RefrEnv
REM https://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w
REM ___USAGE_____________________________________________________________
REM usage:
REM call refrenv.bat full refresh. refresh all non critical variables*, and refresh the PATH
REM debug:
REM to debug what this script do create this variable in your parent script like that
REM set debugme=yes
REM then the folder containing the files used to set the variables will be open. Then see
REM _NewEnv.cmd this is the file which run inside your script to setup the new variables, you
REM can also revise the intermediate files _NewEnv.cmd_temp_.cmd and _NewEnv.cmd_temp2_.cmd
REM (those two contains all the variables before removing the duplicates and the unwanted variables)
REM you can also put this script in windows\systems32 or another place in your %PATH% then call it from an interactive console by writing refrenv
REM *critical variables: are variables which belong to cmd/windows and should not be refreshed normally like:
REM - windows vars:
REM ALLUSERSPROFILE APPDATA CommonProgramFiles CommonProgramFiles(x86) CommonProgramW6432 COMPUTERNAME ComSpec HOMEDRIVE HOMEPATH LOCALAPPDATA LOGONSERVER NUMBER_OF_PROCESSORS OS PATHEXT PROCESSOR_ARCHITECTURE PROCESSOR_ARCHITEW6432 PROCESSOR_IDENTIFIER PROCESSOR_LEVEL PROCESSOR_REVISION ProgramData ProgramFiles ProgramFiles(x86) ProgramW6432 PUBLIC SystemDrive SystemRoot TEMP TMP USERDOMAIN USERDOMAIN_ROAMINGPROFILE USERNAME USERPROFILE windir SESSIONNAME
REM ___INFO_____________________________________________________________
REM :: this script reload environment variables inside cmd every time you want environment changes to propagate, so you do not need to restart cmd after setting a new variable with setx or when installing new apps which add new variables ...etc
REM This is a better alternative to the chocolatey refreshenv for cmd, which solves a lot of problems like:
REM The Chocolatey refreshenv is so bad if the variable have some cmd meta-characters, see this test:
REM add this to the path in HKCU\Environment: test & echo baaaaaaaaaad, and run the chocolatey refreshenv you will see that it prints baaaaaaaaaad which is very bad, and the new path is not added to your path variable.
REM This script solve this and you can test it with any meta-character, even something so bad like:
REM ; & % ' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
REM refreshenv adds only system and user environment variables, but CMD adds volatile variables too (HKCU\Volatile Environment). This script will merge all the three and remove any duplicates.
REM refreshenv reset your PATH. This script append the new path to the old path of the parent script which called this script. It is better than overwriting the old path, otherwise it will delete any newly added path by the parent script.
REM This script solve this problem described in a comment by @Gene Mayevsky: refreshenv modifies env variables TEMP and TMP replacing them with values stored in HKCU\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that's running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\AppData\Local\Temp instead of C:\Windows\Temp. This breaks build because linker cannot open system profile's Temp folder.
REM ________
REM this script solve things like that too:
REM The confusing thing might be that there are a few places to start the cmd from. In my case I run cmd from windows explorer and the environment variables did not change while when starting cmd from the "run" (windows key + r) the environment variables were changed.
REM In my case I just had to kill the windows explorer process from the task manager and then restart it again from the task manager.
REM Once I did this I had access to the new environment variable from a cmd that was spawned from windows explorer.
REM my conclusion:
REM if I add a new variable with setx, i can access it in cmd only if i run cmd as admin, without admin right i have to restart explorer to see that new variable. but running this script inside my script (who sets the variable with setx) solve this problem and i do not have to restart explorer
REM ________
REM windows recreate the path using three places at less:
REM the User namespace: HKCU\Environment
REM the System namespace: HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
REM the Session namespace: HKCU\Volatile Environment
REM but the original chocolatey script did not add the volatile path. This script will merge all the three and remove any duplicates. this is what windows do by default too
REM there is this too which cmd seems to read when first running, but it contains only TEMP and TMP,so i will not use it
REM HKEY_USERS\.DEFAULT\Environment
REM ___TESTING_____________________________________________________________
REM to test this script with extreme cases do
REM :: Set a bad variable
REM add a var in reg HKCU\Environment as the following, and see that echo is not executed. if you use refreshenv of chocolatey you will see that echo is executed which is so bad!
REM so save this in reg:
REM all 32 characters: & % ' ( ) ~ + @ # $ { } [ ] ; , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
REM and this:
REM (^.*)(Form Product=")([^"]*") FormType="[^"]*" FormID="([0-9][0-9]*)".*$
REM and use set to print those variables and see if they are saved without change ; refreshenv fail dramatically with those variables
REM invalid characters (illegal characters in file names) in Windows using NTFS
REM \ / : * ? " < > | and ^ in FAT
REM __________________________________________________________________________________________
REM __________________________________________________________________________________________
REM __________________________________________________________________________________________
REM this is a hybrid script which call vbs from cmd directly
REM :: The only restriction is the batch code cannot contain - - > (without space between - - > of course)
REM :: The only restriction is the VBS code cannot contain </script>.
REM :: The only risk is the undocumented use of "%~f0?.wsf" as the script to load. Somehow the parser properly finds and loads the running .BAT script "%~f0", and the ?.wsf suffix mysteriously instructs CSCRIPT to interpret the script as WSF. Hopefully MicroSoft will never disable that "feature".
REM :: https://stackoverflow.com/questions/9074476/is-it-possible-to-embed-and-execute-vbscript-within-a-batch-file-without-using-a
if "%debugme%"=="yes" (
echo RefrEnv - Refresh the Environment for CMD - ^(Debug enabled^)
) else (
echo RefrEnv - Refresh the Environment for CMD
)
set "TEMPDir=%TEMP%\refrenv"
IF NOT EXIST "%TEMPDir%" mkdir "%TEMPDir%"
set "outputfile=%TEMPDir%\_NewEnv.cmd"
REM detect if DelayedExpansion is enabled
REM It relies on the fact, that the last caret will be removed only in delayed mode.
REM https://www.dostips.com/forum/viewtopic.php?t=6496
set "DelayedExpansionState=IsDisabled"
IF "^!" == "^!^" (
REM echo DelayedExpansion is enabled
set "DelayedExpansionState=IsEnabled"
)
REM :: generate %outputfile% which contain all the new variables
REM cscript //nologo "%~f0?.wsf" %1
cscript //nologo "%~f0?.wsf" "%outputfile%" %DelayedExpansionState%
REM ::set the new variables generated with vbscript script above
REM for this to work always it is necessary to use DisableDelayedExpansion or escape ! and ^ when using EnableDelayedExpansion, but this script already solve this, so no worry about that now, thanks to God
REM test it with some bad var like:
REM all 32 characters: ; & % ' ( ) ~ + @ # $ { } [ ] , ` ! ^ | > < \ / " : ? * = . - _ & echo baaaad
REM For /f delims^=^ eol^= %%a in (%outputfile%) do %%a
REM for /f "delims== tokens=1,2" %%G in (%outputfile%) do set "%%G=%%H"
For /f delims^=^ eol^= %%a in (%outputfile%) do set %%a
REM for safely print a variable with bad charachters do:
REM SETLOCAL EnableDelayedExpansion
REM echo "!z9!"
REM or
REM set z9
REM but generally paths and environment variables should not have bad metacharacters, but it is not a rule!
if "%debugme%"=="yes" (
explorer "%TEMPDir%"
) else (
rmdir /Q /S "%TEMPDir%"
)
REM cleanup
set "TEMPDir="
set "outputfile="
set "DelayedExpansionState="
set "debugme="
REM pause
exit /b
REM #############################################################################
REM :: to run jscript you have to put <script language="JScript"> directly after ----- Begin wsf script --->
----- Begin wsf script --->
<job><script language="VBScript">
REM #############################################################################
REM ### put you code here #######################################################
REM #############################################################################
REM based on itsadok script from here
REM https://stackoverflow.com/questions/171588/is-there-a-command-to-refresh-environment-variables-from-the-command-prompt-in-w
REM and it is faster as stated by this comment
REM While I prefer the Chocolatey code-wise for being pure batch code, overall I decided to use this one, since it's faster. (~0.3 seconds instead of ~1 second -- which is nice, since I use it frequently in my Explorer "start cmd here" entry) –
REM and it is safer based on my tests, the Chocolatey refreshenv is so bad if the variable have some cmd metacharacters
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Set WshShell = WScript.CreateObject("WScript.Shell")
filename=WScript.Arguments.Item(0)
DelayedExpansionState=WScript.Arguments.Item(1)
TMPfilename=filename & "_temp_.cmd"
Set fso = CreateObject("Scripting.fileSystemObject")
Set tmpF = fso.CreateTextFile(TMPfilename, TRUE)
set oEnvS=WshShell.Environment("System")
for each sitem in oEnvS
tmpF.WriteLine(sitem)
next
SystemPath = oEnvS("PATH")
set oEnvU=WshShell.Environment("User")
for each sitem in oEnvU
tmpF.WriteLine(sitem)
next
UserPath = oEnvU("PATH")
set oEnvV=WshShell.Environment("Volatile")
for each sitem in oEnvV
tmpF.WriteLine(sitem)
next
VolatilePath = oEnvV("PATH")
set oEnvP=WshShell.Environment("Process")
REM i will not save the process env but only its path, because it have strange variables like =::=::\ and =F:=.... which seems to be added by vbscript
REM for each sitem in oEnvP
REM tmpF.WriteLine(sitem)
REM next
REM here we add the actual session path, so we do not reset the original path, because maybe the parent script added some folders to the path, If we need to reset the path then comment the following line
ProcessPath = oEnvP("PATH")
REM merge System, User, Volatile, and process PATHs
NewPath = SystemPath & ";" & UserPath & ";" & VolatilePath & ";" & ProcessPath
REM ________________________________________________________________
REM :: remove duplicates from path
REM :: expand variables so they become like windows do when he read reg and create path, then Remove duplicates without sorting
REM why i will clean the path from duplicates? because:
REM the maximum string length in cmd is 8191 characters. But string length doesnt mean that you can save 8191 characters in a variable because also the assignment belongs to the string. you can save 8189 characters because the remaining 2 characters are needed for "a="
REM based on my tests:
REM when i open cmd as user , windows does not remove any duplicates from the path, and merge system+user+volatil path
REM when i open cmd as admin, windows do: system+user path (here windows do not remove duplicates which is stupid!) , then it adds volatil path after removing from it any duplicates
REM ' https://www.rosettacode.org/wiki/Remove_duplicate_elements#VBScript
Function remove_duplicates(list)
arr = Split(list,";")
Set dict = CreateObject("Scripting.Dictionary")
REM ' force dictionary compare to be case-insensitive , uncomment to force case-sensitive
dict.CompareMode = 1
For i = 0 To UBound(arr)
If dict.Exists(arr(i)) = False Then
dict.Add arr(i),""
End If
Next
For Each key In dict.Keys
tmp = tmp & key & ";"
Next
remove_duplicates = Left(tmp,Len(tmp)-1)
End Function
REM expand variables
NewPath = WshShell.ExpandEnvironmentStrings(NewPath)
REM remove duplicates
NewPath=remove_duplicates(NewPath)
REM remove_duplicates() will add a ; to the end so lets remove it if the last letter is ;
If Right(NewPath, 1) = ";" Then
NewPath = Left(NewPath, Len(NewPath) - 1)
End If
tmpF.WriteLine("PATH=" & NewPath)
tmpF.Close
REM ________________________________________________________________
REM :: exclude setting variables which may be dangerous to change
REM when i run a script from task scheduler using SYSTEM user the following variables are the differences between the scheduler env and a normal cmd script, so i will not override those variables
REM APPDATA=D:\Users\LLED2\AppData\Roaming
REM APPDATA=D:\Windows\system32\config\systemprofile\AppData\Roaming
REM LOCALAPPDATA=D:\Users\LLED2\AppData\Local
REM LOCALAPPDATA=D:\Windows\system32\config\systemprofile\AppData\Local
REM TEMP=D:\Users\LLED2\AppData\Local\Temp
REM TEMP=D:\Windows\TEMP
REM TMP=D:\Users\LLED2\AppData\Local\Temp
REM TMP=D:\Windows\TEMP
REM USERDOMAIN=LLED2-PC
REM USERDOMAIN=WORKGROUP
REM USERNAME=LLED2
REM USERNAME=LLED2-PC$
REM USERPROFILE=D:\Users\LLED2
REM USERPROFILE=D:\Windows\system32\config\systemprofile
REM i know this thanks to this comment
REM The solution is good but it modifies env variables TEMP and TMP replacing them with values stored in HKCU\Environment. In my case I run the script to update env variables modified by Jenkins job on a slave that's running under SYSTEM account, so TEMP and TMP get substituted by %USERPROFILE%\AppData\Local\Temp instead of C:\Windows\Temp. This breaks build because linker cannot open system profile's Temp folder. – Gene Mayevsky Sep 26 '19 at 20:51
REM Delete Lines of a Text File Beginning with a Specified String
REM those are the variables which should not be changed by this script
arrBlackList = Array("ALLUSERSPROFILE=", "APPDATA=", "CommonProgramFiles=", "CommonProgramFiles(x86)=", "CommonProgramW6432=", "COMPUTERNAME=", "ComSpec=", "HOMEDRIVE=", "HOMEPATH=", "LOCALAPPDATA=", "LOGONSERVER=", "NUMBER_OF_PROCESSORS=", "OS=", "PATHEXT=", "PROCESSOR_ARCHITECTURE=", "PROCESSOR_ARCHITEW6432=", "PROCESSOR_IDENTIFIER=", "PROCESSOR_LEVEL=", "PROCESSOR_REVISION=", "ProgramData=", "ProgramFiles=", "ProgramFiles(x86)=", "ProgramW6432=", "PUBLIC=", "SystemDrive=", "SystemRoot=", "TEMP=", "TMP=", "USERDOMAIN=", "USERDOMAIN_ROAMINGPROFILE=", "USERNAME=", "USERPROFILE=", "windir=", "SESSIONNAME=")
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objTS = objFS.OpenTextFile(TMPfilename, ForReading)
strContents = objTS.ReadAll
objTS.Close
TMPfilename2= filename & "_temp2_.cmd"
arrLines = Split(strContents, vbNewLine)
Set objTS = objFS.OpenTextFile(TMPfilename2, ForWriting, True)
REM this is the equivalent of findstr /V /I /L or grep -i -v , i don t know a better way to do it, but it works fine
For Each strLine In arrLines
bypassThisLine=False
For Each BlackWord In arrBlackList
If Left(UCase(LTrim(strLine)),Len(BlackWord)) = UCase(BlackWord) Then
bypassThisLine=True
End If
Next
If bypassThisLine=False Then
objTS.WriteLine strLine
End If
Next
REM ____________________________________________________________
REM :: expand variables because registry save some variables as unexpanded %....%
REM :: and escape ! and ^ for cmd EnableDelayedExpansion mode
set f=fso.OpenTextFile(TMPfilename2,ForReading)
REM Write file: ForAppending = 8 ForReading = 1 ForWriting = 2 , True=create file if not exist
set fW=fso.OpenTextFile(filename,ForWriting,True)
Do Until f.AtEndOfStream
LineContent = f.ReadLine
REM expand variables
LineContent = WshShell.ExpandEnvironmentStrings(LineContent)
REM _____this part is so important_____
REM if cmd delayedexpansion is enabled in the parent script which calls this script then bad thing happen to variables saved in the registry if they contain ! . if var have ! then ! and ^ are removed; if var do not have ! then ^ is not removed . to understand what happens read this :
REM how cmd delayed expansion parse things
REM https://stackoverflow.com/questions/4094699/how-does-the-windows-command-interpreter-cmd-exe-parse-scripts/7970912#7970912
REM For each parsed token, first check if it contains any !. If not, then the token is not parsed - important for ^ characters. If the token does contain !, then scan each character from left to right:
REM - If it is a caret (^) the next character has no special meaning, the caret itself is removed
REM - If it is an exclamation mark, search for the next exclamation mark (carets are not observed anymore), expand to the value of the variable.
REM - Consecutive opening ! are collapsed into a single !
REM - Any remaining unpaired ! is removed
REM ...
REM Look at next string of characters, breaking before !, :, or <LF>, and call them VAR
REM conclusion:
REM when delayedexpansion is enabled and var have ! then i have to escape ^ and ! ,BUT IF VAR DO NOT HAVE ! THEN DO NOT ESCAPE ^ .this made me crazy to discover
REM when delayedexpansion is disabled then i do not have to escape anything
If DelayedExpansionState="IsEnabled" Then
If InStr(LineContent, "!") > 0 Then
LineContent=Replace(LineContent,"^","^^")
LineContent=Replace(LineContent,"!","^!")
End If
End If
REM __________
fW.WriteLine(LineContent)
Loop
f.Close
fW.Close
REM #############################################################################
REM ### end of vbscript code ####################################################
REM #############################################################################
REM this must be at the end for the hybrid trick, do not remove it
</script></job>
+4
View File
@@ -0,0 +1,4 @@
urllib3==1.26.18
requests==2.32.3
pystray==0.19.5
dnspython==2.7.0
-4
View File
@@ -1,4 +0,0 @@
urllib3==1.26.18
requests==2.31.0
pystray==0.19.5
dnspython==2.6.1
+124 -57
View File
@@ -1,52 +1,118 @@
@echo off
setlocal enabledelayedexpansion
cd /d "%~dp0"
set NAME=HotspotAutoLogin
set RUN=HotspotAutoLogin.pyw
set "requirementsFile=requirements.txt"
set PROJECTFOLDER=main
set RUN=%PROJECTFOLDER%\HotspotAutoLogin.pyw
set requirementsFile=%PROJECTFOLDER%\requirements.txt
set VENV_PATH=.venv
set ACTIVATE_PATH=%VENV_PATH%\Scripts\activate
set CURRENT_DIR=%CD%
set LAST_DIR_FILE=%PROJECTFOLDER%\last_known_directory.txt
set refrenv=%PROJECTFOLDER%\refrenv.bat
set PYTHON_DOWNLOAD_URL=https://www.python.org/ftp/python/3.12.4/python-3.12.4-amd64.exe
:: Display provided argument if any
if not "%~1"=="" (
echo Open with: "%~1"
)
:: Check if Python is installed
pip --version >nul 2>&1
if errorlevel 1 (
echo Python is not installed.
set /p "userinp=Do you want to install Python (y/n)? "
if /i "!userinp!"=="y" (
echo Opening download link...
start https://www.python.org/downloads/
exit /b
pip --version >nul 2>&1 && (set python_installed=true) || (set python_installed=false)
if not "%python_installed%"=="true" (
echo Python is required to run this program.
set /p "userinp=Do you want to install Python (y/n)?: "
if /i "!userinp!"=="y" (
echo Downloading Python...
winget install python --accept-package-agreements
if errorlevel 1 (
echo Download failed using winget method. Trying to download manually...
:bothwingetfailed
if not exist "%PROJECTFOLDER%\python_installer.exe" (
echo Downloading Python from %PYTHON_DOWNLOAD_URL%
curl %PYTHON_DOWNLOAD_URL% -o %PROJECTFOLDER%\python_installer.exe
if not exist "%PROJECTFOLDER%\python_installer.exe" (
echo Download failed using curl. Trying with the powershell method
powershell -Command "& {Invoke-WebRequest -Uri '%PYTHON_DOWNLOAD_URL%' -OutFile '%PROJECTFOLDER%\python_installer.exe'}"
if errorlevel 1 (
echo Failed to install Python. Please install Python manually and try again.
pause
exit /b
)
)
)
echo Installing Python. Please wait...
start /wait %PROJECTFOLDER%\python_installer.exe /quiet InstallAllUsers=1 PrependPath=1 Include_test=0
if errorlevel 1 (
echo Failed to install Python. Please install Python manually and try again.
pause
exit /b
)
del %PROJECTFOLDER%\python_installer.exe
goto python_ok
)
) else (
echo Please install Python and try again.
pause
exit /b
echo Python is required to run this program. Please install Python and try again.
pause
exit /b
)
:python_ok
echo Python installed successfully.
:: Refresh the environment variables
call %refrenv%
set python_installed=true
)
:: Check if virtual environment exists
IF NOT EXIST %VENV_PATH% (
echo Creating virtual environment...
python -m venv %VENV_PATH%
echo Creating virtual environment...
echo %CURRENT_DIR% > "%LAST_DIR_FILE%"
python -m venv %VENV_PATH%
) ELSE (
goto check_python
goto check_python
)
:: Check if Python exists at the path stored in the virtual environment
set counut_python=0
set count_python=0
:check_python
%VENV_PATH%\Scripts\python.exe --version >nul 2>&1
if %errorlevel% neq 0 (
set /a count_python+=1
echo Python not found at the path stored in the virtual environment.
echo Recreating virtual environment...
rmdir /s /q %VENV_PATH%
python -m venv %VENV_PATH%
if !count_python! lss 3 (
goto check_python
) else (
echo Something went wrong. Please try again.
pause
exit /b
)
set /a count_python+=1
echo Python not found at the path stored in the virtual environment.
echo Recreating virtual environment...
rmdir /s /q %VENV_PATH%
python -m venv %VENV_PATH%
if !count_python! lss 3 (
goto check_python
) else (
echo Something went wrong. Please try again.
pause
exit /b
)
)
:: Check if the current directory has changed since the last run
if exist "%LAST_DIR_FILE%" (
set /p last_dir=<"%LAST_DIR_FILE%"
cd "%CURRENT_DIR%" && (
if not exist "!last_dir!" (
echo Current directory: %CURRENT_DIR%
echo Last known directory: !last_dir!
echo Looks like the directory of the program has been changed.
echo It is hihgly recommended to recreate the virtual environment.
set /p "recreate_venv=Recreate the virtual environment (y/n)?: "
if /i "!recreate_venv!"=="y" (
echo Recreating virtual environment...
rmdir /s /q %VENV_PATH%
python -m venv %VENV_PATH%
:: Update the last directory file
echo %CURRENT_DIR% > "%LAST_DIR_FILE%"
)
)
)
) else (
:: Create the last directory file if it doesn't exist
echo %CURRENT_DIR% > "%LAST_DIR_FILE%"
)
:: Activate the virtual environment
@@ -55,45 +121,46 @@ set count_activate=0
echo Activating virtual environment...
call %ACTIVATE_PATH%
if errorlevel 1 (
set /a count_activate+=1
echo Failed to activate virtual environment.
echo Recreating virtual environment...
rmdir /s /q %VENV_PATH%
python -m venv %VENV_PATH%
if !count_activate! lss 3 (
goto activate
) else (
echo Failed to activate virtual environment. Please try again.
pause
exit /b
)
set /a count_activate+=1
echo Failed to activate virtual environment.
echo Recreating virtual environment...
rmdir /s /q %VENV_PATH%
python -m venv %VENV_PATH%
if !count_activate! lss 3 (
goto activate
) else (
echo Failed to activate virtual environment. Please try again.
pause
exit /b
)
)
:: Get the list of installed packages using pip freeze
echo Checking the requirements...
for /f "tokens=1,* delims==" %%i in ('pip freeze') do (
set installed[%%i]=%%j
for /f "tokens=1,* delims==" %%i in ('pip freeze --all') do (
set installed[%%i]=%%j
)
:: Compare with the requirements from the requirements.txt file
for /f "tokens=1,* delims==" %%i in (%requirementsFile%) do (
if not "!installed[%%i]!"=="%%j" (
echo Installing package: %%i==%%j
pip install %%i==%%j --upgrade --quiet
if errorlevel 1 (
echo Failed to install %%i==%%j. Please check your internet connection and try again.
pause
exit /b
)
)
if not "!installed[%%i]!"=="%%j" (
echo Installing package: %%i==%%j
pip install %%i==%%j --upgrade --quiet
if errorlevel 1 (
echo Failed to install %%i==%%j. Please check your internet connection and try again.
pause
exit /b
)
)
)
:: Run the program
echo Starting %NAME%...
start /B "" "%VENV_PATH%/Scripts/pythonw.exe" %RUN%
start /B "" "%VENV_PATH%\Scripts\pythonw.exe" %RUN% %* > nul 2>&1
if errorlevel 1 (
echo Failed to start %NAME%. Please try again.
pause
exit /b
echo Failed to start %NAME%. Please try again.
pause
exit /b
)
exit /b
exit /b