master
1#!/usr/bin/python
2
3import ConfigParser
4import requests
5import optparse
6import sys
7
8
9# This is a command-line script to update a hover.com DNS record with your
10# current public-facing IP address. (think dyndns) Run it like so:
11# ./dynhover.py -u USERNAME -p PASSWORD DOMAIN
12# or create a config file like this:
13#
14# [hover]
15# username=USERNAME
16# password=PASSWORD
17#
18# and run it like this:
19# ./dynhover.py -c PATH_TO_CONF DOMAIN
20
21
22class HoverException(Exception):
23 pass
24
25
26class HoverAPI(object):
27 def __init__(self, username, password):
28 params = {"username": username, "password": password}
29 r = requests.post("https://www.hover.com/api/login", params=params)
30 if not r.ok or "hoverauth" not in r.cookies:
31 raise HoverException(r)
32 self.cookies = {"hoverauth": r.cookies["hoverauth"]}
33 def call(self, method, resource, data=None):
34 url = "https://www.hover.com/api/{0}".format(resource)
35 r = requests.request(method, url, data=data, cookies=self.cookies)
36 if not r.ok:
37 raise HoverException(r)
38 if r.content:
39 body = r.json()
40 if "succeeded" not in body or body["succeeded"] is not True:
41 raise HoverException(body)
42 return body
43
44
45def get_public_ip():
46 return requests.get("http://api.exip.org/?call=ip").content
47
48
49def update_dns(username, password, fqdn):
50 try:
51 client = HoverAPI(username, password)
52 except HoverException as e:
53 raise HoverException("Authentication failed")
54 dns = client.call("get", "dns")
55 dns_id = None
56 for domain in dns["domains"]:
57 if fqdn == domain["domain_name"]:
58 fqdn = "@.{domain_name}".format(**domain)
59 for entry in domain["entries"]:
60 if entry["type"] != "A": continue
61 if "{0}.{1}".format(entry["name"], domain["domain_name"]) == fqdn:
62 dns_id = entry["id"]
63 break
64 if dns_id is None:
65 raise HoverException("No DNS record found for {0}".format(fqdn))
66
67 my_ip = get_public_ip()
68
69 response = client.call("put", "dns/{0}".format(dns_id), {"content": my_ip})
70
71 if "succeeded" not in response or response["succeeded"] is not True:
72 raise HoverException(response)
73
74
75def main():
76 usage = "usage: %prog (-c CONF|-u USERNAME -p PASSWORD) DOMAIN"
77 description = "Update a hover.com DNS record with the current IP of this machine."
78 parser = optparse.OptionParser(usage=usage, description=description)
79 parser.add_option("-c", "--conf", default=None, help="The conf file that contains your username and password")
80 parser.add_option("-u", "--username", default=None, help="Your hover.com username")
81 parser.add_option("-p", "--password", default=None, help="Your hover.com password")
82 (options, args) = parser.parse_args()
83
84 if len(args) < 1:
85 parser.error("You must specify a domain")
86
87 domain = args[0]
88
89 def get_conf(filename):
90 config = ConfigParser.ConfigParser()
91 config.read(filename)
92 items = dict(config.items("hover"))
93 return items["username"], items["password"]
94
95 if options.conf is None:
96 if not all((options.username, options.password)):
97 parser.error("You must specifiy either a conf file, or a username and password")
98 else:
99 username, password = options.username, options.password
100 else:
101 username, password = get_conf(options.conf)
102
103 update_dns(username, password, domain)
104
105
106if __name__ == "__main__":
107 try:
108 main()
109 except HoverException as e:
110 print "Unable to update DNS: {0}".format(e)
111 sys.exit(1)
112 sys.exit(0)