def update_hostname(session: Session, hostnames: list, target_hostname_name: str, new_ip: str) -> None: target_hostnames = [ hostname for hostname in hostnames if hostname["hostname"] == target_hostname_name ] if not target_hostnames: neg(f"No hostname called \"{target_hostname_name}\"!") return pos(f"Updating hostname \"{target_hostname_name}\" to point to \"{new_ip}\"." ) target_hostname = target_hostnames[0] target_hostname["target"] = new_ip url = HOSTNAME_PUT_URL % target_hostname["id"] response = session.put(url, json.dumps(target_hostname), headers={"Content-Type": "application/json"}) if response.status_code == 200: pos("Success.") else: neg("Failure.")
def ddns_set_hostnames(session: Session, hostname_names: list, ip: str) -> None: pos(f"({datetime.now()}) Updating hostnames {hostname_names} to point to \"{ip}\"." ) url = URL_DDNS_UPDATE % (",".join(hostname_names), ip) if (rsp := session.get(url)).status_code != 200: neg(f"Error {rsp.status_code}")
def verify_hostnames_exist(hostname_names: list, hostnames: list) -> None: existing_hostnames = [ hostname for hostname in hostnames if hostname["hostname"] in hostname_names ] if len(hostname_names) != len(existing_hostnames): neg("Hostnames do not exist.") sys.exit(-1)
def login(username: str, password: str) -> Session: session = Session() # Obtain a CSRF token token_response = session.get(URL_LOGIN_PAGE) token = EXTRACTOR_LOGIN_TOKEN.search(token_response.text).group(1) # FIXME: I think this broke because they now require a captcha pos(f"Extracted login token \"{token}\".") pos(f"Logging in as \"{username}\"...") login_response = session.post(URL_LOGIN_PAGE, data={ "username": username, "password": password, "submit_login_page": "1", "_token": token, }) if TOKEN_RATE_LIMITED in login_response.text: neg("Rate limited.") sys.exit(-1) if TOKEN_LOGIN_SUCCESS not in login_response.text: neg("Login failed.") sys.exit(-1) main_page_response = session.get(URL_DYNAMIC_DNS_PAGE) csrf_token = EXTRACTOR_CSRF_TOKEN.search(main_page_response.text).group(1) # Set up some disguise headers. # We might get an "403 - Unauthorized" without this. session.headers["X-Requested-With"] = "XMLHttpRequest" session.headers["X-CSRF-TOKEN"] = csrf_token session.headers["Referer"] = HEADER_REFERER session.headers["Origin"] = HEADER_ORIGIN session.headers["User-Agent"] = USER_AGENT pos(f"Extracted CSRF token \"{csrf_token}\".") pos("Login succeeded.") return session
def __call__(self) -> str: url, func = next(self.__services) try: with requests.get(url) as rsp: if rsp.status_code != 200: neg(f"Error! Response code {rsp.status_code} from \"{url}\"!" ) return self() # There is at least one service that occasionally gives # an error html page. Do some error checking. ip: str = func(rsp) if not ip.replace(".", "").isdecimal(): neg(f"Error parsing output from \"{url}\"!") return self() return ip except RequestException: neg(f"Error connecting to \"{url}\"!") return self()