mirror of
https://github.com/Stone-Red-Code/HotspotAutoLogin.git
synced 2026-11-01 23:05:40 +01:00
Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12c5808dd0 | ||
|
|
e9428675e9 | ||
|
|
53bf01733e | ||
|
|
bbbb76d577 | ||
|
|
8c7b735cb1 | ||
|
|
9b6d42aff5 | ||
|
|
337c84e9a4 | ||
|
|
bcbad5b8f8 | ||
|
|
f55f09079a | ||
|
|
7ec6601554 | ||
|
|
10c3b7f233 | ||
|
|
bbc9be3b93 | ||
|
|
2ff513099f | ||
|
|
54eea0ad63 | ||
|
|
fee77034f4 | ||
|
|
af880b0e92 | ||
|
|
c495415df9 | ||
|
|
10436f0b4f | ||
|
|
95e62523f4 | ||
|
|
05471f19ac | ||
|
|
dcf2b5426f | ||
|
|
79f792f0b0 | ||
|
|
1f0b3d7de1 | ||
|
|
c7fec03add | ||
|
|
cb6c8d5ffd | ||
|
|
638e888e83 | ||
|
|
ff2ac683bf | ||
|
|
585d8d11d7 | ||
|
|
ed01a946b6 | ||
|
|
224e5625a7 | ||
|
|
37fc8a6a76 | ||
|
|
9d511650f6 | ||
|
|
bad72f479a | ||
|
|
55bfb8c07d | ||
|
|
dd966d353d | ||
|
|
89d6f1017d | ||
|
|
90fbc78b85 | ||
|
|
101ed1c714 | ||
|
|
f59a79070b |
+27
@@ -0,0 +1,27 @@
|
||||
# macOS system files
|
||||
.DS_Store
|
||||
._*
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Python artifacts
|
||||
__pycache__/
|
||||
**/__pycache__
|
||||
*.py[cod]
|
||||
*.so
|
||||
*.exe
|
||||
*.zip
|
||||
*.tar.gz
|
||||
|
||||
# Virtual environments
|
||||
env/
|
||||
venv/
|
||||
.env/
|
||||
.venv/
|
||||
|
||||
# VS Code settings
|
||||
.vscode/
|
||||
# Runtime files
|
||||
main/log.txt
|
||||
main/session_state.json
|
||||
main/last_known_directory.txt
|
||||
@@ -1,500 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
import time
|
||||
import subprocess
|
||||
import pystray
|
||||
import threading
|
||||
import tkinter as tk
|
||||
from tkinter import Text, Scrollbar
|
||||
from PIL import Image
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
import dns.resolver
|
||||
dns.resolver.override_system_resolver(dns.resolver.Resolver())
|
||||
dns.resolver.default_resolver = dns.resolver.Resolver()
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
||||
|
||||
# Function to center a window on the screen
|
||||
def center_window(window, width, height):
|
||||
screen_width = window.winfo_screenwidth()
|
||||
screen_height = window.winfo_screenheight()
|
||||
x = (screen_width - width) // 2
|
||||
y = (screen_height - height) // 2
|
||||
window.geometry(f"{width}x{height}+{x}+{y}")
|
||||
|
||||
def run_profile():
|
||||
global selected_profile
|
||||
refresh_profile_details()
|
||||
selected_index = listbox.curselection()
|
||||
if selected_index:
|
||||
selected_index = int(selected_index[0])
|
||||
selected_profile = profiles[selected_index]
|
||||
root.destroy()
|
||||
|
||||
# Define a function to update the profile details
|
||||
def update_profile_details(event):
|
||||
global selected_profile
|
||||
selected_index = listbox.curselection()
|
||||
if selected_index:
|
||||
selected_index = int(selected_index[0])
|
||||
selected_profile = profiles[selected_index]
|
||||
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
|
||||
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.config(state=tk.DISABLED)
|
||||
else:
|
||||
profile_name.config(text="Selected Profile: ")
|
||||
profile_details.config(state=tk.NORMAL)
|
||||
profile_details.delete(1.0, tk.END)
|
||||
profile_details.config(state=tk.DISABLED)
|
||||
|
||||
# Function to refresh the profile details
|
||||
def refresh_profile_details():
|
||||
global profiles
|
||||
# Get the index of the currently selected profile
|
||||
selected_index = listbox.curselection()
|
||||
selected_index = int(selected_index[0]) if selected_index else None
|
||||
# Reload configuration from file
|
||||
with open("config.json", "r") as f:
|
||||
config = json.load(f)
|
||||
profiles = config.get("profiles", [])
|
||||
listbox.delete(0, tk.END) # Clear the listbox
|
||||
for profile in profiles:
|
||||
listbox.insert(tk.END, profile['name'])
|
||||
# Reselect the previously selected profile if it exists
|
||||
if selected_index is not None and selected_index < len(profiles):
|
||||
listbox.select_set(selected_index)
|
||||
update_profile_details(None)
|
||||
|
||||
# Function to open the config file
|
||||
def open_config():
|
||||
subprocess.Popen(["start", "config.json"], shell=True)
|
||||
|
||||
# Load configuration from file
|
||||
with open("config.json", "r") as f:
|
||||
config = json.load(f)
|
||||
|
||||
# Get the list of profiles
|
||||
profiles = config.get("profiles", [])
|
||||
|
||||
# Create the main window
|
||||
root = tk.Tk()
|
||||
root.title("Profile Selection")
|
||||
|
||||
# Set a maximum size for the window
|
||||
width = 850
|
||||
height = 300
|
||||
root.minsize(width, height) # Adjust the values as needed
|
||||
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 listbox to display available profiles
|
||||
listbox = tk.Listbox(profiles_frame, selectmode=tk.SINGLE)
|
||||
listbox.pack(side=tk.LEFT, fill=tk.Y)
|
||||
|
||||
for profile in profiles:
|
||||
listbox.insert(tk.END, profile['name'])
|
||||
|
||||
# Create a vertical scrollbar for the listbox
|
||||
scrollbar = tk.Scrollbar(profiles_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
|
||||
listbox.bind('<<ListboxSelect>>', lambda event: (update_profile_details(event), refresh_profile_details()))
|
||||
listbox.bind('<Return>', run_profile) # Run the selected profile when the Enter key is pressed
|
||||
|
||||
# Create a frame for displaying profile details
|
||||
details_frame = tk.Frame(root)
|
||||
details_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||||
|
||||
# Create a frame for the profile name and the Refresh button
|
||||
profile_name_frame = tk.Frame(details_frame)
|
||||
profile_name_frame.pack(fill="x", pady=(0, 5))
|
||||
|
||||
# Create the label for the selected profile name
|
||||
profile_name = tk.Label(profile_name_frame, text="Selected Profile: ", anchor="w")
|
||||
profile_name.pack(side=tk.LEFT)
|
||||
|
||||
# Create a Text widget for displaying profile details with a fixed height and scrollbars
|
||||
profile_details = Text(details_frame, wrap=tk.WORD, height=10, state=tk.DISABLED, exportselection=False)
|
||||
profile_details.pack(fill="both", expand=True)
|
||||
|
||||
# Create a vertical scrollbar for the profile details Text widget
|
||||
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()
|
||||
os._exit(0)
|
||||
|
||||
root.protocol("WM_DELETE_WINDOW", on_closing)
|
||||
|
||||
# Create the "Refresh" button within the profile name frame
|
||||
refresh_button = tk.Button(
|
||||
profile_name_frame,
|
||||
text="Refresh",
|
||||
command=refresh_profile_details,
|
||||
padx=5,
|
||||
pady=0,
|
||||
fg="white",
|
||||
bg="grey",
|
||||
activebackground="#606060",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
refresh_button.pack(side=tk.RIGHT)
|
||||
|
||||
# Create the "Config" button
|
||||
config_button = tk.Button(
|
||||
details_frame,
|
||||
text="Config",
|
||||
command=open_config,
|
||||
padx=30,
|
||||
pady=10,
|
||||
fg="white",
|
||||
bg="grey",
|
||||
activebackground="#606060",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
config_button.pack(side=tk.LEFT, fill="x", padx=(0, 2), pady=(10, 0), expand=False)
|
||||
|
||||
# Create the "Run" button
|
||||
run_button = tk.Button(
|
||||
details_frame,
|
||||
text="Run",
|
||||
command=run_profile,
|
||||
padx=10,
|
||||
pady=10,
|
||||
fg="white",
|
||||
bg="#08872a",
|
||||
activebackground="#076921",
|
||||
activeforeground="white",
|
||||
relief=tk.RAISED,
|
||||
borderwidth=2,
|
||||
)
|
||||
run_button.pack(side=tk.LEFT, fill="x", padx=(2, 0), pady=(10, 0), expand=True)
|
||||
|
||||
# Configure weights for horizontal stretching
|
||||
details_frame.pack_propagate(False)
|
||||
|
||||
# Start with no profile selected
|
||||
selected_profile = None
|
||||
|
||||
# Select the first profile by default
|
||||
if profiles:
|
||||
selected_profile = profiles[0]
|
||||
listbox.select_set(0) # Highlight the first item in the list
|
||||
update_profile_details(None) # Update the profile details
|
||||
|
||||
root.mainloop()
|
||||
|
||||
# Access the selected profile's data after the window closes
|
||||
if selected_profile:
|
||||
payload = selected_profile.get('payload')
|
||||
url = selected_profile.get('url', "")
|
||||
ssid = selected_profile.get('ssid', "")
|
||||
check_every_second = selected_profile.get('check_every_second', "")
|
||||
dialog_geometry = selected_profile.get('dialog_geometry', "")
|
||||
headers = selected_profile.get('headers', "")
|
||||
if ssid:
|
||||
expected_ssid = ssid
|
||||
expected_ssid_lower = expected_ssid.lower()
|
||||
else:
|
||||
ssid = "Ethernet"
|
||||
expected_ssid = ssid
|
||||
expected_ssid_lower = None
|
||||
|
||||
# Function to send the request
|
||||
def send_request():
|
||||
session = requests.Session()
|
||||
requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL'
|
||||
response = session.post(url, json.dumps(payload), headers=headers, allow_redirects=True, verify=False, timeout=3)
|
||||
response.raise_for_status() # Check for HTTP errors
|
||||
return response
|
||||
|
||||
# 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:
|
||||
return False
|
||||
|
||||
# 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
|
||||
# Get 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
|
||||
elif wifi_ssid is None:
|
||||
# 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")
|
||||
for line in ethernet_lines:
|
||||
if "Connected" in line:
|
||||
if "Ethernet" in line:
|
||||
return "Ethernet"
|
||||
else:
|
||||
return False
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
# Function to exit the application
|
||||
def exit_application(icon, item):
|
||||
icon.stop()
|
||||
os._exit(0)
|
||||
|
||||
# Queue to store log messages
|
||||
log_messages = deque(maxlen=15)
|
||||
log_dialog = None
|
||||
log_text = None
|
||||
log_dialog_open = False
|
||||
|
||||
# Get the dialog geometry from the config file
|
||||
width = dialog_geometry["width"]
|
||||
height = dialog_geometry["height"]
|
||||
x = 0
|
||||
y = 0
|
||||
|
||||
# Function to update the window's position and size variables
|
||||
def update_window_geometry(event):
|
||||
global x, y, width, height
|
||||
x, y = event.x, event.y
|
||||
width, height = event.width, event.height
|
||||
|
||||
# Function to show the log dialog with the currently selected profile name
|
||||
def show_log_dialog():
|
||||
global log_dialog, log_text, log_dialog_open
|
||||
if not log_dialog_open:
|
||||
log_dialog_open = True
|
||||
if log_dialog:
|
||||
log_dialog.title(f"Log Messages ({selected_profile['name']})") # Update title with profile name
|
||||
log_dialog.deiconify()
|
||||
update_log()
|
||||
else:
|
||||
log_dialog = tk.Tk()
|
||||
log_dialog.title(f"Log Messages ({selected_profile['name']})") # Update title with profile name
|
||||
log_text = tk.Text(log_dialog)
|
||||
log_frame = tk.Frame(log_dialog)
|
||||
log_frame.pack(fill=tk.BOTH, expand=True)
|
||||
log_text = tk.Text(log_frame, wrap=tk.WORD)
|
||||
log_text.pack(fill=tk.BOTH, expand=True)
|
||||
update_log()
|
||||
log_dialog.protocol("WM_DELETE_WINDOW", hide_log_dialog)
|
||||
center_window(log_dialog, width, height)
|
||||
log_dialog.bind("<Configure>", update_window_geometry)
|
||||
log_dialog.mainloop()
|
||||
else:
|
||||
hide_log_dialog()
|
||||
|
||||
# Function to hide the log dialog
|
||||
def hide_log_dialog():
|
||||
global log_dialog, log_text, log_dialog_open
|
||||
log_dialog_open = False
|
||||
if log_dialog:
|
||||
log_dialog.withdraw()
|
||||
log_dialog = None
|
||||
log_text = None
|
||||
|
||||
# Function to get the last log messages
|
||||
def get_last_log_messages():
|
||||
global log_messages
|
||||
return list(log_messages)
|
||||
|
||||
# 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")
|
||||
|
||||
# Function to add a message to the log
|
||||
def add_to_log(message):
|
||||
global log_messages
|
||||
now = datetime.now()
|
||||
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_messages.append(f"({timestamp}) {message}")
|
||||
update_log()
|
||||
|
||||
# Function to add a message to the log file (txt)
|
||||
def save_to_file(message):
|
||||
# Get the current date and time
|
||||
now = datetime.now()
|
||||
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:
|
||||
f.write(formatted_message)
|
||||
|
||||
# Create the system tray icon
|
||||
def create_system_tray_icon():
|
||||
image = Image.open("icon.ico")
|
||||
menu = pystray.Menu(
|
||||
pystray.MenuItem('Show Log', show_log_dialog, default=True),
|
||||
pystray.MenuItem('Exit', exit_application)
|
||||
)
|
||||
icon = pystray.Icon("my_icon", image, "HotspotAutoLogin", menu)
|
||||
icon.run()
|
||||
|
||||
# Function to check network status
|
||||
running = True
|
||||
errorcount = 0
|
||||
request_success = False
|
||||
request_errorcount = 0
|
||||
sleepcount = check_every_second
|
||||
connected_ssid_lower = None
|
||||
def check_network_status():
|
||||
global running, errorcount, sleepcount, connected_ssid_lower, ssid, response, request_success, request_errorcount
|
||||
while running and errorcount < 10:
|
||||
connected_ssid = get_connected_network()
|
||||
if (connected_ssid):
|
||||
connected_ssid_lower = connected_ssid.lower()
|
||||
if (connected_ssid) and ((connected_ssid_lower == expected_ssid_lower) or (connected_ssid == "Ethernet")):
|
||||
if (is_internet_available()):
|
||||
sleepcount = check_every_second
|
||||
message = "Connected to {} and internet connection is available. Checking again in {} seconds...".format(connected_ssid, str(sleepcount))
|
||||
errorcount = 0
|
||||
add_to_log(message)
|
||||
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)
|
||||
save_to_file(message)
|
||||
else:
|
||||
sleepcount = 3
|
||||
message = "Connected to {} but internet is down. Sending the request...".format(connected_ssid)
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
time.sleep(sleepcount)
|
||||
# Send the request and handle potential errors
|
||||
try:
|
||||
# Function to send request
|
||||
response = send_request()
|
||||
if response.ok:
|
||||
errorcount = 0
|
||||
sleepcount = 10
|
||||
request_success = True
|
||||
request_errorcount = 0
|
||||
message = "Request was successful. Checking the internet connection in {} seconds...".format(str(sleepcount))
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
except requests.exceptions.RequestException as e:
|
||||
errorcount += 1
|
||||
sleepcount = 1
|
||||
request_success = False
|
||||
if isinstance(e, requests.exceptions.HTTPError):
|
||||
# Handle HTTP errors with different messages for different status codes
|
||||
status_code = e.response.status_code
|
||||
if status_code == 400:
|
||||
message = "Request failed with 400 Bad Request error. Please check your payload and URL. Trying to reconnect to the network... (Errors: {}/10)".format(errorcount)
|
||||
elif status_code == 404:
|
||||
message = "Request failed with 404 Not Found error. Trying to reconnect to the network... (Errors: {}/10)".format(errorcount)
|
||||
elif status_code == 500:
|
||||
message = "Request failed with 500 Internal Server Error. Trying to reconnect to the network... (Errors: {}/10)".format(errorcount)
|
||||
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)
|
||||
else:
|
||||
message = "Request failed with error:{}. Trying to reconnect to the network... (Errors: {}/10)".format(e, errorcount)
|
||||
# Print the response message
|
||||
add_to_log(message)
|
||||
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
|
||||
message = "Disconnecting from Ethernet..."
|
||||
add_to_log(message)
|
||||
subprocess.check_output(['ipconfig', '/release', "Ethernet"], shell=True, text=True)
|
||||
time.sleep(5)
|
||||
subprocess.check_output(['ipconfig', '/renew', "Ethernet"], shell=True, text=True)
|
||||
message = "Connected to Ethernet. Running the script again..."
|
||||
add_to_log(message)
|
||||
time.sleep(5)
|
||||
except Exception as e:
|
||||
message += "\nFailed to reconnect to Ethernet: {}".format(e)
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
else:
|
||||
try:
|
||||
# Disconnect and reconnect to the Wi-Fi network
|
||||
message = "Disconnecting from {}...".format(ssid)
|
||||
add_to_log(message)
|
||||
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)
|
||||
time.sleep(5)
|
||||
except Exception as e:
|
||||
message += "\nFailed to reconnect to {}: {}".format(ssid, e)
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
continue
|
||||
else:
|
||||
sleepcount = 10 # Sleep ... seconds before trying again
|
||||
message = "Not connected to {} or any other network. Checking again in {} seconds...".format(expected_ssid, str(sleepcount))
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
|
||||
time.sleep(sleepcount) # Sleep ... seconds before trying again
|
||||
|
||||
message = "Maximum error count reached. Exiting in 5 seconds..."
|
||||
add_to_log(message)
|
||||
save_to_file(message)
|
||||
time.sleep(5)
|
||||
running = False
|
||||
os._exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Create a thread for the system tray icon
|
||||
tray_thread = threading.Thread(target=create_system_tray_icon)
|
||||
tray_thread.start()
|
||||
# Open Log Messages at startup
|
||||
open_log_messages_startup = threading.Thread(target=show_log_dialog)
|
||||
open_log_messages_startup.start()
|
||||
# Start the network status checking in the main thread
|
||||
check_network_status()
|
||||
# Wait for all threads to finish
|
||||
tray_thread.join()
|
||||
@@ -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`
|
||||
@@ -26,12 +26,24 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
- Any important events or actions taken by the script are logged both in a log file (log.txt) and in the log window that can be accessed via the system tray icon.
|
||||
- The script reads its configuration from a config.json file. This file contains the necessary information, such as your login credentials, the URL of the authentication portal, the SSID (network name) to which you want to connect, and the frequency of network checks in seconds.
|
||||
|
||||
## `Auto Mode & Start with Windows`
|
||||
- **Auto mode:** Click the **Auto** button in the profile selection window (or run with `--auto`). Instead of using a single profile, the program looks at the network you are actually connected to and picks the matching profile automatically:
|
||||
- **Wi-Fi:** the profile whose `ssid` matches the connected Wi-Fi (case-insensitive).
|
||||
- **Ethernet:** profiles without an `ssid` are Ethernet profiles. The one whose login `url` is reachable on the current network is used.
|
||||
- If the connected network doesn't match any profile, nothing is sent and the program just waits for a known network. It never forces a connection to another network in this mode.
|
||||
- `config.json` is re-read on every check, so edits apply without restarting.
|
||||
- **Start with Windows:** Tick **Start with Windows (Auto)** in the profile selection window. The program will then start at sign-in in Auto mode, in the background (tray icon only). Untick it to disable. This uses the current user's `Run` registry key, so no admin rights are needed.
|
||||
- Command line flags: `--auto` (skip profile selection, use Auto mode) and `--background` (don't open the log window at startup). E.g. `run.bat --auto`.
|
||||
|
||||
## `Usage`
|
||||
- Edit the config.json file with your specific information, including your login credentials, the portal URL, the SSID of the network you want to connect to, and the check interval in seconds. [Click to learn how to Configure the config.json](#how-to-configure-the-configjson)
|
||||
- When you run the script, a system tray icon will appear. Right-click on the icon to access options like showing the log or exiting the application.
|
||||
- To check the connection right away instead of waiting for the next check, click **Check Now** in the tray menu or in the log window. If the internet is down, it logs in immediately.
|
||||
- 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 recently, added "Add new" button to the program, so you can achieve the same thing without needing to edit the config.json.
|
||||
|
||||

|
||||
|
||||
@@ -46,6 +58,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.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -53,6 +67,8 @@ HotspotAutoLogin is a script that designed to automate the login process for Wi-
|
||||
|
||||
`"check_every_second":` The frequency of the script for checking your internet connection status. For example "100", it will try to check the internet every 100 seconds.
|
||||
|
||||
`"session_hours":` *(optional)* If your network logs you out a fixed time after logging in (for example every 24 hours), enter that here, e.g. `24`. The program remembers when it last logged in (in `session_state.json`) and checks the connection every 5 seconds from 2 minutes before the expected expiry until 10 minutes after it, so you are logged back in within seconds instead of waiting for the next `check_every_second` check.
|
||||
|
||||
> ## Example useage:
|
||||
>
|
||||
|
||||
@@ -60,9 +76,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 +96,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 +115,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 |
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
@@ -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>
|
||||
@@ -0,0 +1,4 @@
|
||||
urllib3==1.26.18
|
||||
requests==2.32.3
|
||||
pystray==0.19.5
|
||||
dnspython==2.7.0
|
||||
@@ -1,4 +0,0 @@
|
||||
urllib3==1.26.18
|
||||
requests==2.31.0
|
||||
pystray==0.19.5
|
||||
dnspython==2.6.1
|
||||
@@ -1,69 +1,166 @@
|
||||
@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 count_python=0
|
||||
:check_python
|
||||
%VENV_PATH%\Scripts\python.exe --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
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%
|
||||
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
|
||||
set count_activate=0
|
||||
:activate
|
||||
echo Activating virtual environment...
|
||||
call %ACTIVATE_PATH%
|
||||
if errorlevel 1 (
|
||||
echo Failed to activate virtual environment.
|
||||
echo Recreating virtual environment...
|
||||
rmdir /s /q %VENV_PATH%
|
||||
python -m venv %VENV_PATH%
|
||||
echo Activating virtual environment...
|
||||
call %ACTIVATE_PATH%
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
echo Checking the requirements...
|
||||
:: Get the list of installed packages using pip freeze
|
||||
for /f "tokens=1,* delims==" %%i in ('pip freeze') do (
|
||||
set installed[%%i]=%%j
|
||||
echo Checking the requirements...
|
||||
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 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
|
||||
)
|
||||
|
||||
exit /b
|
||||
|
||||
Reference in New Issue
Block a user