|
@@ -0,0 +1,135 @@
|
|
|
|
|
+import time
|
|
|
|
|
+import requests
|
|
|
|
|
+import smtplib
|
|
|
|
|
+from email.mime.text import MIMEText
|
|
|
|
|
+import configparser
|
|
|
|
|
+
|
|
|
|
|
+# Load configuration from config.ini
|
|
|
|
|
+config = configparser.ConfigParser()
|
|
|
|
|
+config.read('config/config.ini')
|
|
|
|
|
+
|
|
|
|
|
+if not config.sections():
|
|
|
|
|
+ raise ValueError("Config file 'config.ini' not found or empty. Please create it with the required settings.")
|
|
|
|
|
+
|
|
|
|
|
+# General settings
|
|
|
|
|
+CHECK_INTERVAL = config.getint('General', 'check_interval', fallback=300) # Unused in one-shot mode, but kept for reference
|
|
|
|
|
+NOTIFY_METHODS_STR = config.get('General', 'notify_methods', fallback='email') # Comma-separated string, default to 'email'
|
|
|
|
|
+LAST_IP_FILE = config.get('General', 'last_ip_file', fallback='last_ip.txt')
|
|
|
|
|
+
|
|
|
|
|
+# Parse notify_methods into a list (strip whitespace, lowercase, remove duplicates)
|
|
|
|
|
+NOTIFY_METHODS = list(set(m.strip().lower() for m in NOTIFY_METHODS_STR.split(',') if m.strip()))
|
|
|
|
|
+if not NOTIFY_METHODS:
|
|
|
|
|
+ NOTIFY_METHODS = ['email'] # Default to email if empty or invalid
|
|
|
|
|
+
|
|
|
|
|
+# Email settings
|
|
|
|
|
+EMAIL_FROM = config.get('Email', 'from', fallback='')
|
|
|
|
|
+EMAIL_TO = config.get('Email', 'to', fallback='')
|
|
|
|
|
+SMTP_SERVER = config.get('Email', 'server', fallback='')
|
|
|
|
|
+SMTP_PORT = config.getint('Email', 'port', fallback=465)
|
|
|
|
|
+SMTP_USER = config.get('Email', 'user', fallback='')
|
|
|
|
|
+SMTP_PASS = config.get('Email', 'pass', fallback='')
|
|
|
|
|
+
|
|
|
|
|
+# Telegram settings
|
|
|
|
|
+TELEGRAM_BOT_TOKEN = config.get('Telegram', 'bot_token', fallback='')
|
|
|
|
|
+TELEGRAM_CHAT_ID = config.get('Telegram', 'chat_id', fallback='')
|
|
|
|
|
+
|
|
|
|
|
+# Nextcloud Talk settings
|
|
|
|
|
+NEXTCLOUD_URL = config.get('Nextcloud', 'url', fallback='')
|
|
|
|
|
+NEXTCLOUD_TOKEN = config.get('Nextcloud', 'token', fallback='')
|
|
|
|
|
+NEXTCLOUD_ROOM = config.get('Nextcloud', 'room', fallback='')
|
|
|
|
|
+
|
|
|
|
|
+def get_public_ip():
|
|
|
|
|
+ try:
|
|
|
|
|
+ return requests.get("https://api.ipify.org").text.strip()
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"Error getting public IP: {e}")
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+def send_email(subject, body):
|
|
|
|
|
+ if not all([EMAIL_FROM, EMAIL_TO, SMTP_SERVER, SMTP_USER, SMTP_PASS]):
|
|
|
|
|
+ print("Email settings incomplete in config.")
|
|
|
|
|
+ return False
|
|
|
|
|
+ try:
|
|
|
|
|
+ msg = MIMEText(body)
|
|
|
|
|
+ msg["Subject"] = subject
|
|
|
|
|
+ msg["From"] = EMAIL_FROM
|
|
|
|
|
+ msg["To"] = EMAIL_TO
|
|
|
|
|
+ with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
|
|
|
|
|
+ server.set_debuglevel(1)
|
|
|
|
|
+ # server.starttls() # Commented as in original; using SSL
|
|
|
|
|
+ server.login(SMTP_USER, SMTP_PASS)
|
|
|
|
|
+ server.sendmail(EMAIL_FROM, EMAIL_TO, msg.as_string())
|
|
|
|
|
+ return True
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"Error sending email: {e}")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+def send_telegram(message):
|
|
|
|
|
+ if not all([TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID]):
|
|
|
|
|
+ print("Telegram settings incomplete in config.")
|
|
|
|
|
+ return False
|
|
|
|
|
+ try:
|
|
|
|
|
+ url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
|
|
|
|
|
+ data = {"chat_id": TELEGRAM_CHAT_ID, "text": message}
|
|
|
|
|
+ response = requests.post(url, data=data)
|
|
|
|
|
+ return response.status_code == 200
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"Error sending Telegram message: {e}")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+def send_nextcloud_talk(message):
|
|
|
|
|
+ if not all([NEXTCLOUD_URL, NEXTCLOUD_TOKEN, NEXTCLOUD_ROOM]):
|
|
|
|
|
+ print("Nextcloud settings incomplete in config.")
|
|
|
|
|
+ return False
|
|
|
|
|
+ try:
|
|
|
|
|
+ url = f"{NEXTCLOUD_URL}/ocs/v2.php/apps/spreed/api/v1/chat/{NEXTCLOUD_ROOM}"
|
|
|
|
|
+ headers = {
|
|
|
|
|
+ "OCS-APIRequest": "true",
|
|
|
|
|
+ "Authorization": f"Bearer {NEXTCLOUD_TOKEN}"
|
|
|
|
|
+ }
|
|
|
|
|
+ data = {"message": message}
|
|
|
|
|
+ response = requests.post(url, headers=headers, data=data)
|
|
|
|
|
+ return response.status_code == 200
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ print(f"Error sending Nextcloud message: {e}")
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+def notify(ip):
|
|
|
|
|
+ message = f"Public IP changed to: {ip}"
|
|
|
|
|
+ for method in NOTIFY_METHODS:
|
|
|
|
|
+ if method == "email":
|
|
|
|
|
+ success = send_email("IP Address Changed", message)
|
|
|
|
|
+ print(f"Email notification {'sent' if success else 'failed'}.")
|
|
|
|
|
+ elif method == "telegram":
|
|
|
|
|
+ success = send_telegram(message)
|
|
|
|
|
+ print(f"Telegram notification {'sent' if success else 'failed'}.")
|
|
|
|
|
+ elif method == "nextcloud":
|
|
|
|
|
+ success = send_nextcloud_talk(message)
|
|
|
|
|
+ print(f"Nextcloud notification {'sent' if success else 'failed'}.")
|
|
|
|
|
+ else:
|
|
|
|
|
+ print(f"Unknown notification method: {method}. Skipping.")
|
|
|
|
|
+
|
|
|
|
|
+def load_last_ip():
|
|
|
|
|
+ try:
|
|
|
|
|
+ with open(LAST_IP_FILE, "r") as f:
|
|
|
|
|
+ return f.read().strip()
|
|
|
|
|
+ except FileNotFoundError:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+def save_last_ip(ip):
|
|
|
|
|
+ with open(LAST_IP_FILE, "w") as f:
|
|
|
|
|
+ f.write(ip)
|
|
|
|
|
+
|
|
|
|
|
+def main():
|
|
|
|
|
+ last_ip = load_last_ip()
|
|
|
|
|
+ while True:
|
|
|
|
|
+ print("Checking for public IP...")
|
|
|
|
|
+ ip = get_public_ip()
|
|
|
|
|
+ if ip and ip != last_ip:
|
|
|
|
|
+ notify(ip)
|
|
|
|
|
+ save_last_ip(ip)
|
|
|
|
|
+ last_ip = ip
|
|
|
|
|
+ time.sleep(CHECK_INTERVAL)
|
|
|
|
|
+
|
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
|
+ main()
|