From a5e831ec213549660e5b6c811f480a23c42acb6d Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Thu, 30 May 2019 22:00:21 +0200 Subject: [PATCH 1/5] Fix regexes --- whoisdb/validators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/whoisdb/validators.py b/whoisdb/validators.py index e30dedd..3cc9b52 100644 --- a/whoisdb/validators.py +++ b/whoisdb/validators.py @@ -14,7 +14,7 @@ import ipaddress @deconstructible class HandleValidator(validators.RegexValidator): - regex = r'^(?:[A-Z]+[0-9]*(-[A-Z]+)|AUTO)' + regex = r'^(?:[A-Z]+[0-9]*(-[A-Z]+)|AUTO)$' message = _( 'Enter a valid handle (all uppercase)' ) @@ -26,7 +26,7 @@ class HandleValidatorWithSuffix(validators.RegexValidator): flags = re.ASCII if six.PY3 else 0 def __init__(self, suffix): - self.regex = r'^(?:[A-Z]+[0-9]*-%s|AUTO)' % re.escape(suffix) + self.regex = r'^(?:[A-Z]+[0-9]*-%s|AUTO)$' % re.escape(suffix) self.message = _( 'Enter a valid handle with suffix %s (all uppercase), e.g. FOO3-%s' % (suffix, suffix) ) From 83843115173504fcd567546888510c5b434dc55c Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Thu, 30 May 2019 22:10:55 +0200 Subject: [PATCH 2/5] Replace tabs with spaces --- api/dnshelper.py | 212 ++++++------- api/urls.py | 12 +- api/views.py | 368 ++++++++++----------- bin/dns-sync | 301 +++++++++--------- bin/import-data | 194 +++++------ bin/markdown-to-html | 8 +- bin/roa-export | 28 +- bin/whoisd | 130 ++++---- dncore/forms.py | 6 +- dncore/models.py | 2 +- dncore/urls.py | 10 +- dncore/views.py | 64 ++-- dnmgmt/settings.py | 104 +++--- dnmgmt/urls.py | 16 +- domains/forms.py | 378 +++++++++++----------- domains/models.py | 226 ++++++------- domains/urls.py | 30 +- domains/views.py | 186 +++++------ rrequests/forms.py | 68 ++-- rrequests/models.py | 64 ++-- rrequests/urls.py | 6 +- rrequests/views.py | 142 ++++----- whoisdb/formfields.py | 52 +-- whoisdb/forms.py | 494 ++++++++++++++--------------- whoisdb/generic.py | 68 ++-- whoisdb/helpers.py | 280 ++++++++-------- whoisdb/models.py | 402 +++++++++++------------ whoisdb/templatetags/handletags.py | 46 +-- whoisdb/urls.py | 52 +-- whoisdb/validators.py | 36 +-- whoisdb/views.py | 472 +++++++++++++-------------- 31 files changed, 2228 insertions(+), 2229 deletions(-) diff --git a/api/dnshelper.py b/api/dnshelper.py index 03b6559..4734c61 100644 --- a/api/dnshelper.py +++ b/api/dnshelper.py @@ -11,121 +11,121 @@ import dns.resolver # FIXME: DNS timeouts def compareRecords(rrset, expected): - result = { - "nameMissing": [], - "rrMissing": [], - "rrExtra": [], - } + result = { + "nameMissing": [], + "rrMissing": [], + "rrExtra": [], + } - for domain, rrtype, content in expected: - for rrrec in rrset: - if domain == rrrec.name.to_text() and dns.rdatatype.from_text(rrtype) == rrrec.rdtype: - for name in content: - if name not in map(lambda _x: _x.to_text(), rrrec.items): - # record missing - result["rrMissing"].append((domain, rrtype, name)) + for domain, rrtype, content in expected: + for rrrec in rrset: + if domain == rrrec.name.to_text() and dns.rdatatype.from_text(rrtype) == rrrec.rdtype: + for name in content: + if name not in map(lambda _x: _x.to_text(), rrrec.items): + # record missing + result["rrMissing"].append((domain, rrtype, name)) - for item in rrrec.items: - if item.to_text() not in content: - # superfluous record - result["rrExtra"].append((domain, rrtype, item.to_text())) + for item in rrrec.items: + if item.to_text() not in content: + # superfluous record + result["rrExtra"].append((domain, rrtype, item.to_text())) - break - else: - # domain + rr nicht in nameserver - result["nameMissing"].append((domain, rrtype)) + break + else: + # domain + rr nicht in nameserver + result["nameMissing"].append((domain, rrtype)) - success = not any(len(_x) > 0 for _x in result.values()) + success = not any(len(_x) > 0 for _x in result.values()) - return success, result + return success, result def dnsQuery(domain, rrType, nameserverIp): - dname = dns.name.from_text(domain) - req = dns.message.make_query(dname, dns.rdatatype.from_text(rrType)) - resp = dns.query.udp(req, nameserverIp, timeout=2.0) + dname = dns.name.from_text(domain) + req = dns.message.make_query(dname, dns.rdatatype.from_text(rrType)) + resp = dns.query.udp(req, nameserverIp, timeout=2.0) - if resp.rcode() != dns.rcode.NXDOMAIN: - rrset = resp.answer + resp.authority + resp.additional - return True, rrset - else: - return False, [] + if resp.rcode() != dns.rcode.NXDOMAIN: + rrset = resp.answer + resp.authority + resp.additional + return True, rrset + else: + return False, [] def checkDomain(domain, tldNameserver, nameservers): - result = [] - - if nameservers.count() == 0: - return [("err", "Domain %s has no nameservers attached to it, nothing to check" % domain)] - - # build record set - nsRecords = [(domain, "NS", list(ns.name for ns in nameservers))] - glueRecords = [] - for ns in nameservers: - if ns.name.endswith("." + domain): - if ns.glueIPv4 or ns.glueIPv6: - if ns.glueIPv4: - glueRecords.append((ns.name, "A", [ns.glueIPv4])) - if ns.glueIPv6: - glueRecords.append((ns.name, "AAAA", [ns.glueIPv6])) - else: - result.append(("err", "Nameserver %s is under domain %s, but has no glue entries." % (ns.name, domain))) - - # 1. TLD nameserver - try: - found, rrset = dnsQuery(domain, "ANY", tldNameserver) - if found: - success, errors = compareRecords(rrset, nsRecords + glueRecords) - if success: - result.append(("succ", "All records present in TLD nameserver")) - else: - result.append(("err", "Record mismatch between TLD nameserver and WHOIS database", errors)) - else: - result.append(("err", "Domain %s not found in TLD nameserver" % (domain,))) - except (dns.exception.Timeout, OSError): - result.append(("err", "TLD nameserver is currently not reachable")) - - # find other records... - - # 2. your nameservers - for ns in nameservers: - addr = None - if ns.glueIPv4: - addr = ns.glueIPv4 - elif ns.glueIPv6: - addr = ns.glueIPv6 - else: - for rrType in ("A", "AAAA"): - try: - r = dns.resolver.Resolver() - r.timeout = 2.0 - q = r.query(ns.name, rdtype=dns.rdatatype.from_text(rrType)) - addr = q.response.answer[0].items[0].address - except (dns.exception.DNSException, OSError): - pass - - if addr: - err = False - errDict = {"nameMissing": [], "rrMissing": [], "rrExtra": []} - try: - for rec in (nsRecords + glueRecords): - found, rrset = dnsQuery(rec[0], rec[1], addr) - - #success, errors = compareRecords(rrset, nsRecords + glueRecords) - success, errors = compareRecords(rrset, [rec]) - if not success: - err = True - for k in errors.keys(): - errDict[k].extend(errors[k]) - - if not err: - result.append(("succ", "Nameserver %s is configured correctly" % ns.name)) - else: - result.append(("err", "Nameserver %s (via %s) recordset does not match the database" % (ns.name, addr), errDict)) - except (dns.exception.DNSException, OSError): - result.append(("err", "Nameserver %s is not reachable (via %s)" % (ns.name, addr))) - - else: - result.append(("err", "Can't resolv an ip address for nameserver %s" % ns.name)) - - return result + result = [] + + if nameservers.count() == 0: + return [("err", "Domain %s has no nameservers attached to it, nothing to check" % domain)] + + # build record set + nsRecords = [(domain, "NS", list(ns.name for ns in nameservers))] + glueRecords = [] + for ns in nameservers: + if ns.name.endswith("." + domain): + if ns.glueIPv4 or ns.glueIPv6: + if ns.glueIPv4: + glueRecords.append((ns.name, "A", [ns.glueIPv4])) + if ns.glueIPv6: + glueRecords.append((ns.name, "AAAA", [ns.glueIPv6])) + else: + result.append(("err", "Nameserver %s is under domain %s, but has no glue entries." % (ns.name, domain))) + + # 1. TLD nameserver + try: + found, rrset = dnsQuery(domain, "ANY", tldNameserver) + if found: + success, errors = compareRecords(rrset, nsRecords + glueRecords) + if success: + result.append(("succ", "All records present in TLD nameserver")) + else: + result.append(("err", "Record mismatch between TLD nameserver and WHOIS database", errors)) + else: + result.append(("err", "Domain %s not found in TLD nameserver" % (domain,))) + except (dns.exception.Timeout, OSError): + result.append(("err", "TLD nameserver is currently not reachable")) + + # find other records... + + # 2. your nameservers + for ns in nameservers: + addr = None + if ns.glueIPv4: + addr = ns.glueIPv4 + elif ns.glueIPv6: + addr = ns.glueIPv6 + else: + for rrType in ("A", "AAAA"): + try: + r = dns.resolver.Resolver() + r.timeout = 2.0 + q = r.query(ns.name, rdtype=dns.rdatatype.from_text(rrType)) + addr = q.response.answer[0].items[0].address + except (dns.exception.DNSException, OSError): + pass + + if addr: + err = False + errDict = {"nameMissing": [], "rrMissing": [], "rrExtra": []} + try: + for rec in (nsRecords + glueRecords): + found, rrset = dnsQuery(rec[0], rec[1], addr) + + #success, errors = compareRecords(rrset, nsRecords + glueRecords) + success, errors = compareRecords(rrset, [rec]) + if not success: + err = True + for k in errors.keys(): + errDict[k].extend(errors[k]) + + if not err: + result.append(("succ", "Nameserver %s is configured correctly" % ns.name)) + else: + result.append(("err", "Nameserver %s (via %s) recordset does not match the database" % (ns.name, addr), errDict)) + except (dns.exception.DNSException, OSError): + result.append(("err", "Nameserver %s is not reachable (via %s)" % (ns.name, addr))) + + else: + result.append(("err", "Can't resolv an ip address for nameserver %s" % ns.name)) + + return result diff --git a/api/urls.py b/api/urls.py index 4b88c64..4edb7e7 100644 --- a/api/urls.py +++ b/api/urls.py @@ -7,13 +7,13 @@ from django.conf.urls import url from . import views as api_views urlpatterns = [ - url(r'asblock/free-as/$', api_views.asblockFreeAS, name='asblock-free-as'), - url(r'asblock/free-subnet/$', api_views.freeSubnet, name='inetnum-free-subnet'), - url(r'inetnum/get-subnet/$', api_views.getSubnet, name='inetnum-get-subnet'), + url(r'asblock/free-as/$', api_views.asblockFreeAS, name='asblock-free-as'), + url(r'asblock/free-subnet/$', api_views.freeSubnet, name='inetnum-free-subnet'), + url(r'inetnum/get-subnet/$', api_views.getSubnet, name='inetnum-get-subnet'), - url(r'domain/check/$', api_views.checkDomain, name='domain-check'), - url(r'rzone/check/$', api_views.checkRzone, name='reversezone-check'), + url(r'domain/check/$', api_views.checkDomain, name='domain-check'), + url(r'rzone/check/$', api_views.checkRzone, name='reversezone-check'), - url(r'roa/$', api_views.getROA, name='get-roa'), + url(r'roa/$', api_views.getROA, name='get-roa'), ] diff --git a/api/views.py b/api/views.py index 62e38d0..2ceca2c 100644 --- a/api/views.py +++ b/api/views.py @@ -19,219 +19,219 @@ import ipaddress @login_required def asblockFreeAS(request): - ret = { - "success": False, - "errorMsg": None, - "number": -1, - } - - try: - blockName = request.GET.get('block', None) - if not blockName: - raise ValidationError("No block given") - - try: - mnts = request.user.maintainer_set.all() - block = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=blockName) - if block.asblock_set.count() > 0: - raise ValidationError("AS Block already has sub AS Blocks") - if block.asnumber_set.count() > 0: - num = block.asnumber_set.order_by("-number")[0].number + 1 - if num > block.asEnd: - num = None - for n in range(block.asBegin, block.asEnd + 1): - try: - ASNumber.objects.get(number=n) - except ASNumber.DoesNotExist: - num = n - break - if not num: - raise ValidationError("No free AS Number in block") - ret["number"] = num - else: - ret["number"] = block.asBegin - except ASBlock.DoesNotExist: - raise ValidationError("Could not get AS Block") - - ret["success"] = True - except ValidationError as e: - ret["errorMsg"] = e.message - return JsonResponse(ret) + ret = { + "success": False, + "errorMsg": None, + "number": -1, + } + + try: + blockName = request.GET.get('block', None) + if not blockName: + raise ValidationError("No block given") + + try: + mnts = request.user.maintainer_set.all() + block = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=blockName) + if block.asblock_set.count() > 0: + raise ValidationError("AS Block already has sub AS Blocks") + if block.asnumber_set.count() > 0: + num = block.asnumber_set.order_by("-number")[0].number + 1 + if num > block.asEnd: + num = None + for n in range(block.asBegin, block.asEnd + 1): + try: + ASNumber.objects.get(number=n) + except ASNumber.DoesNotExist: + num = n + break + if not num: + raise ValidationError("No free AS Number in block") + ret["number"] = num + else: + ret["number"] = block.asBegin + except ASBlock.DoesNotExist: + raise ValidationError("Could not get AS Block") + + ret["success"] = True + except ValidationError as e: + ret["errorMsg"] = e.message + return JsonResponse(ret) @login_required def freeSubnet(request): - ret = { - "success": False, - "errorMsg": None, - "network": None, - } - - try: - parentRangeName = request.GET.get('parentRange', None) - if not parentRangeName: - raise ValidationError("No subnet given") - - parentRange = None - try: - mnts = request.user.maintainer_set.all() - parentRange = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=parentRangeName) - except InetNum.DoesNotExist: - raise ValidationError("Parent range does not exist / is not maintained by you") - - prefixLen = 0 - try: - prefixLen = request.GET.get("prefixLen", None) - if not prefixLen: - if parentRange.protocol == InetNum.IPv4: - prefixLen = 27 - else: - prefixLen = 60 - prefixLen = int(prefixLen) - - if prefixLen < 8 or \ - (parentRange.protocol == InetNum.IPv4 and prefixLen > 32) or \ - (parentRange.protocol == InetNum.IPv6 and prefixLen > 128): - raise ValidationError("Given prefix length is out of range") - except ValueError: - raise ValidationError("PrefixLen is not a number") - - usableNet = None - # FIXME: use first biggest usable netblock... - #biggestNet = parentRange.inetnum_set.order_by("-address") - #if biggestNet - # candidateNet = - # and (biggestNet.getNetwork().broadcast_address.: - - # try using next network in range - # ordering does not work, as order_by sorts alphabetically - # ==> the set is short, we can iterate through all. no sense in unpacking the SQL magic - #biggestNets = parentRange.inetnum_set.order_by("-address") - biggestNet = None - for ipRange in parentRange.inetnum_set.all(): - if not biggestNet or ipRange.getNetwork() > biggestNet: - biggestNet = ipRange.getNetwork() - - if biggestNet: - candidateNet = ipaddress.ip_network("%s/%s" % (biggestNet.broadcast_address + 1, biggestNet.prefixlen)) - print("biggest net", biggestNet, "candidate", candidateNet) - if candidateNet.network_address in parentRange.getNetwork(): - usableNet = candidateNet - - # check if there are still networks left in range - if not usableNet: - # search for free network - nets = list(parentRange.getNetwork().subnets()) - for subRange in parentRange.inetnum_set.all(): - newNet = None - for net in nets: - if subRange.getNetwork().network_address in net: - newNet = net - if not newNet: - # critical error, we want a 500 here - raise ValueError("Subnet not in range") - - nets.remove(newNet) - nets.extend(newNet.address_exclude(subRange.getNetwork())) - - nets = sorted(nets) - for net in nets: - if net.prefixlen <= prefixLen: - usableNet = net - break - - if not usableNet: - raise ValidationError("No space left in given range") - - ret["network"] = "%s/%s" % (usableNet.network_address, prefixLen) - ret["success"] = True - except ValidationError as e: - ret["errorMsg"] = e.message - - return JsonResponse(ret) + ret = { + "success": False, + "errorMsg": None, + "network": None, + } + + try: + parentRangeName = request.GET.get('parentRange', None) + if not parentRangeName: + raise ValidationError("No subnet given") + + parentRange = None + try: + mnts = request.user.maintainer_set.all() + parentRange = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct().get(handle=parentRangeName) + except InetNum.DoesNotExist: + raise ValidationError("Parent range does not exist / is not maintained by you") + + prefixLen = 0 + try: + prefixLen = request.GET.get("prefixLen", None) + if not prefixLen: + if parentRange.protocol == InetNum.IPv4: + prefixLen = 27 + else: + prefixLen = 60 + prefixLen = int(prefixLen) + + if prefixLen < 8 or \ + (parentRange.protocol == InetNum.IPv4 and prefixLen > 32) or \ + (parentRange.protocol == InetNum.IPv6 and prefixLen > 128): + raise ValidationError("Given prefix length is out of range") + except ValueError: + raise ValidationError("PrefixLen is not a number") + + usableNet = None + # FIXME: use first biggest usable netblock... + #biggestNet = parentRange.inetnum_set.order_by("-address") + #if biggestNet + # candidateNet = + # and (biggestNet.getNetwork().broadcast_address.: + + # try using next network in range + # ordering does not work, as order_by sorts alphabetically + # ==> the set is short, we can iterate through all. no sense in unpacking the SQL magic + #biggestNets = parentRange.inetnum_set.order_by("-address") + biggestNet = None + for ipRange in parentRange.inetnum_set.all(): + if not biggestNet or ipRange.getNetwork() > biggestNet: + biggestNet = ipRange.getNetwork() + + if biggestNet: + candidateNet = ipaddress.ip_network("%s/%s" % (biggestNet.broadcast_address + 1, biggestNet.prefixlen)) + print("biggest net", biggestNet, "candidate", candidateNet) + if candidateNet.network_address in parentRange.getNetwork(): + usableNet = candidateNet + + # check if there are still networks left in range + if not usableNet: + # search for free network + nets = list(parentRange.getNetwork().subnets()) + for subRange in parentRange.inetnum_set.all(): + newNet = None + for net in nets: + if subRange.getNetwork().network_address in net: + newNet = net + if not newNet: + # critical error, we want a 500 here + raise ValueError("Subnet not in range") + + nets.remove(newNet) + nets.extend(newNet.address_exclude(subRange.getNetwork())) + + nets = sorted(nets) + for net in nets: + if net.prefixlen <= prefixLen: + usableNet = net + break + + if not usableNet: + raise ValidationError("No space left in given range") + + ret["network"] = "%s/%s" % (usableNet.network_address, prefixLen) + ret["success"] = True + except ValidationError as e: + ret["errorMsg"] = e.message + + return JsonResponse(ret) @login_required def getSubnet(request): - ret = { - "success": False, - "errorMsg": None, - "network": None, - } + ret = { + "success": False, + "errorMsg": None, + "network": None, + } - try: - netName = request.GET.get('net', None) - mnts = request.user.maintainer_set.all() - nets = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - net = nets.get(handle=netName) + try: + netName = request.GET.get('net', None) + mnts = request.user.maintainer_set.all() + nets = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + net = nets.get(handle=netName) - ret["success"] = True - ret["network"] = net.prefix() - except InetNum.DoesNotExist: - ret["errorMsg"] = "Chosen network does not exist" + ret["success"] = True + ret["network"] = net.prefix() + except InetNum.DoesNotExist: + ret["errorMsg"] = "Chosen network does not exist" - return JsonResponse(ret) + return JsonResponse(ret) @login_required def checkDomain(request): - ret = { - "success": False, - "errorMsg": None, - "domain": None, - "result": None, - } + ret = { + "success": False, + "errorMsg": None, + "domain": None, + "result": None, + } - try: - domainName = Domain.fixName(request.GET.get('domain', '')) - domain = Domain.objects.get(name=domainName) - #if not domain.canEdit(request.user): - # raise Domain.DoesNotExist() + try: + domainName = Domain.fixName(request.GET.get('domain', '')) + domain = Domain.objects.get(name=domainName) + #if not domain.canEdit(request.user): + # raise Domain.DoesNotExist() - ret["success"] = True - ret["domain"] = domain.name - # FIXME: change this if we ever have more than one... - ret["result"] = helperCheckDomain(domain.name, TLD_NAMESERVERS[0], domain.nameservers.all()) - except Domain.DoesNotExist: - ret["errorMsg"] = "Domain does not exist" + ret["success"] = True + ret["domain"] = domain.name + # FIXME: change this if we ever have more than one... + ret["result"] = helperCheckDomain(domain.name, TLD_NAMESERVERS[0], domain.nameservers.all()) + except Domain.DoesNotExist: + ret["errorMsg"] = "Domain does not exist" - return JsonResponse(ret) + return JsonResponse(ret) @login_required def checkRzone(request): - ret = { - "success": False, - "errorMsg": None, - "domain": None, - "result": None, - } + ret = { + "success": False, + "errorMsg": None, + "domain": None, + "result": None, + } - try: - rzonePk = int(request.GET.get('domain', '')) - rzone = ReverseZone.objects.get(pk=rzonePk) - #if not rzone.canEdit(request.user): - # raise ReverseZone.DoesNotExist() + try: + rzonePk = int(request.GET.get('domain', '')) + rzone = ReverseZone.objects.get(pk=rzonePk) + #if not rzone.canEdit(request.user): + # raise ReverseZone.DoesNotExist() - ret["success"] = True - # FIXME: change this if we ever have more than one... - ret["result"] = helperCheckDomain(rzone.getZone(), TLD_NAMESERVERS[0], rzone.nameservers.all()) - except (ReverseZone.DoesNotExist, ValueError): - ret["errorMsg"] = "ReverseZone does not exist" + ret["success"] = True + # FIXME: change this if we ever have more than one... + ret["result"] = helperCheckDomain(rzone.getZone(), TLD_NAMESERVERS[0], rzone.nameservers.all()) + except (ReverseZone.DoesNotExist, ValueError): + ret["errorMsg"] = "ReverseZone does not exist" - return JsonResponse(ret) + return JsonResponse(ret) def getROA(request): - roa = {} - for asn in ASNumber.objects.all(): - nets = [] - for net in asn.inetnum_set.all(): - nets.append(net.prefix()) + roa = {} + for asn in ASNumber.objects.all(): + nets = [] + for net in asn.inetnum_set.all(): + nets.append(net.prefix()) - if nets: - roa[asn.number] = nets + if nets: + roa[asn.number] = nets - return JsonResponse(roa) + return JsonResponse(roa) diff --git a/bin/dns-sync b/bin/dns-sync index 4af5e06..67a5eb5 100755 --- a/bin/dns-sync +++ b/bin/dns-sync @@ -25,179 +25,178 @@ __VERSION__ = '0.1' def _parser(): - parser = argparse.ArgumentParser( - #prog='foo', - #description='do some awesome foo', - ) + parser = argparse.ArgumentParser() - parser.add_argument("--pdns-host", default="127.0.0.1", help="PDNS host") - parser.add_argument("--pdns-port", default=8081, help="PDNS port") - parser.add_argument("-c", "--config", default=None, type=argparse.FileType("r"), help="Path to config file (default path: ./dns-sync.conf, /etc/dns-sync.conf)") - parser.add_argument("--api-key", default=None, help="PDNS API key") - parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) + parser.add_argument("--pdns-host", default="127.0.0.1", help="PDNS host") + parser.add_argument("--pdns-port", default=8081, help="PDNS port") + parser.add_argument("-c", "--config", default=None, type=argparse.FileType("r"), help="Path to config file (default path: ./dns-sync.conf, /etc/dns-sync.conf)") + parser.add_argument("--api-key", default=None, help="PDNS API key") + parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) + + return parser - return parser def mergeDomains(zoneData, pdnsData): - rrAdd = [] - rrData = pdnsData['rrsets'] - - for domain, rrType, records in zoneData: - found = False - pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData)) - if len(pdnsDom) > 0: - rrSet = set(_x['content'] for _x in pdnsDom[0]['records']) - if rrSet == set(records): - found = True - - if not found: - # new domain! - rrAdd.append({ - "name": domain, - "type": rrType, - "ttl": 60*60, - "changetype": "REPLACE", - "records": [{"content": record, "disabled": False} for record in records], - }) - - return rrAdd + rrAdd = [] + rrData = pdnsData['rrsets'] + + for domain, rrType, records in zoneData: + found = False + pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData)) + if len(pdnsDom) > 0: + rrSet = set(_x['content'] for _x in pdnsDom[0]['records']) + if rrSet == set(records): + found = True + + if not found: + # new domain! + rrAdd.append({ + "name": domain, + "type": rrType, + "ttl": 60*60, + "changetype": "REPLACE", + "records": [{"content": record, "disabled": False} for record in records], + }) + + return rrAdd def removeOldDomains(zoneData, pdnsData): - rrDel = [] - - #print("zone data", zoneData) - #print("pdnsData", pdnsData) - for entry in pdnsData['rrsets']: - # search for name/type in domain dict. if non-existtant mark for deletion - # this could be much more efficient with a dict! name: [rrset...] - if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in zoneData): - rrDel.append({ - "changetype": "DELETE", - "name": entry["name"], - "type": entry["type"], - }) - - return rrDel + rrDel = [] + + #print("zone data", zoneData) + #print("pdnsData", pdnsData) + for entry in pdnsData['rrsets']: + # search for name/type in domain dict. if non-existtant mark for deletion + # this could be much more efficient with a dict! name: [rrset...] + if not any(entry['name'] == _x[0] and entry['type'] == _x[1] for _x in zoneData): + rrDel.append({ + "changetype": "DELETE", + "name": entry["name"], + "type": entry["type"], + }) + + return rrDel + def handleNameserver(ns, servers, usedNameservers, domains): - servers.append(ns.name) + servers.append(ns.name) - if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): - usedNameservers.append(ns.name) - if ns.glueIPv4: - domains.append((ns.name, "A", [ns.glueIPv4])) - if ns.glueIPv6: - domains.append((ns.name, "AAAA", [ns.glueIPv6])) + if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): + usedNameservers.append(ns.name) + if ns.glueIPv4: + domains.append((ns.name, "A", [ns.glueIPv4])) + if ns.glueIPv6: + domains.append((ns.name, "AAAA", [ns.glueIPv6])) def getDomainsFromQueryset(qs, zone, glueRecords, usedNameservers, v4reverse=False): - for domain in qs: - servers = [] - for ns in domain.nameservers.all(): - servers.append(ns.name) - - if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): - usedNameservers.append(ns.name) - if ns.glueIPv4: - glueRecords.append((ns.name, "A", [ns.glueIPv4])) - if ns.glueIPv6: - glueRecords.append((ns.name, "AAAA", [ns.glueIPv6])) - - zone.append((domain.getZone(), "NS", servers)) - - if v4reverse: - # for ipv4 reverse we have to do some extra work in case of classless delegations - # see RFC2317 - net = domain.parentNet.getNetwork() - if net.prefixlen % 8 != 0: - revZone = domain.getZone() - parts = str(net.network_address).split(".") - baseZone = ".".join(reversed(parts[:net.prefixlen // 8])) + ".in-addr.arpa." - startNo = int(parts[net.prefixlen // 8]) - lenExp = 8 - (net.prefixlen % 8) - - for i in range(2 ** lenExp): - no = startNo + i - zone.append(("%d.%s" % (no, baseZone), "CNAME", ["%d.%s" % (no, revZone)])) + for domain in qs: + servers = [] + for ns in domain.nameservers.all(): + servers.append(ns.name) + + if ns.name not in usedNameservers and (ns.glueIPv4 or ns.glueIPv6): + usedNameservers.append(ns.name) + if ns.glueIPv4: + glueRecords.append((ns.name, "A", [ns.glueIPv4])) + if ns.glueIPv6: + glueRecords.append((ns.name, "AAAA", [ns.glueIPv6])) + + zone.append((domain.getZone(), "NS", servers)) + + if v4reverse: + # for ipv4 reverse we have to do some extra work in case of classless delegations + # see RFC2317 + net = domain.parentNet.getNetwork() + if net.prefixlen % 8 != 0: + revZone = domain.getZone() + parts = str(net.network_address).split(".") + baseZone = ".".join(reversed(parts[:net.prefixlen // 8])) + ".in-addr.arpa." + startNo = int(parts[net.prefixlen // 8]) + lenExp = 8 - (net.prefixlen % 8) + + for i in range(2 ** lenExp): + no = startNo + i + zone.append(("%d.%s" % (no, baseZone), "CNAME", ["%d.%s" % (no, revZone)])) + def mergeDomainsWithPdns(s, args, zone, zoneData, protectedRecords=[]): - url = "http://%s:%s/api/v1/servers/localhost/zones/%s" % (args.pdns_host, args.pdns_port, zone,) - pdnsData = s.get(url).json() + url = "http://%s:%s/api/v1/servers/localhost/zones/%s" % (args.pdns_host, args.pdns_port, zone,) + pdnsData = s.get(url).json() - baseProtectedRecords = [ - (zone, "NS", []), - (zone, "SOA", []), - ] + baseProtectedRecords = [ + (zone, "NS", []), + (zone, "SOA", []), + ] - # add dn. (NS + glue Nameservers) - newDomains = mergeDomains(zoneData, pdnsData) - print("Add/replace", newDomains) + # add dn. (NS + glue Nameservers) + newDomains = mergeDomains(zoneData, pdnsData) + print("Add/replace", newDomains) - if len(newDomains) > 0: - r = s.patch(url, data=json.dumps({'rrsets': newDomains})) - if r.status_code != 204: - raise RuntimeError("Could not update records in powerdns, API returned %d" % r.status_code) + if len(newDomains) > 0: + r = s.patch(url, data=json.dumps({'rrsets': newDomains})) + if r.status_code != 204: + raise RuntimeError("Could not update records in powerdns, API returned %d" % r.status_code) - delDomains = removeOldDomains(zoneData + protectedRecords + baseProtectedRecords, pdnsData) - print("Del", delDomains) - r = s.patch(url, data=json.dumps({'rrsets': delDomains})) - if r.status_code != 204: - raise RuntimeError("Could not update records in powerdns, API returned %d" % r.status_code) + delDomains = removeOldDomains(zoneData + protectedRecords + baseProtectedRecords, pdnsData) + print("Del", delDomains) + r = s.patch(url, data=json.dumps({'rrsets': delDomains})) + if r.status_code != 204: + raise RuntimeError("Could not update records in powerdns, API returned %d" % r.status_code) def main(): - parser = _parser() - args = parser.parse_args() - - config = configparser.ConfigParser() - if args.config: - config.read_file(args.config) - else: - config.read([os.path.join(os.path.abspath(__file__), "dns-sync.conf"), "/etc/dns-sync.conf"]) - #print(config) - #print(config.get("DEFAULT", "api-key")) - #print(config.has_section("DEFAULT"), config.has_option("DEFAULT", "api-key")) - - if args.api_key: - config["DEFAULT"]["api-key"] = args.api_key - - if not config.has_option("DEFAULT", "api-key"): - print("Error: Could not find api-key (not present in config under [DEFAULT]; not given via command line)", file=sys.stderr) - sys.exit(2) - - s = requests.Session() - s.headers = { - 'X-API-Key': config.get("DEFAULT", "api-key"), - 'Accept': 'application/json' - } - - domains = [] - rzone4 = [] - rzone6 = [] - usedNameservers = [] - - # assenble domain data - # dn. - qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") - getDomainsFromQueryset(qs, domains, domains, usedNameservers) - - # reverse zones - qs = ReverseZone.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("parentNet__address") - qs4 = filter(lambda _revz: _revz.getNetwork().version == 4, qs) - qs6 = filter(lambda _revz: _revz.getNetwork().version == 6, qs) - getDomainsFromQueryset(qs4, rzone4, domains, usedNameservers, v4reverse=True) - getDomainsFromQueryset(qs6, rzone6, domains, usedNameservers) - - #print("dn.", domains) - #print("v4", rzone4) - #print("v6", rzone6) - - mergeDomainsWithPdns(s, args, "dn.", domains) - mergeDomainsWithPdns(s, args, "10.in-addr.arpa.", rzone4) - mergeDomainsWithPdns(s, args, "3.2.7.c.3.a.d.f.ip6.arpa.", rzone6) - + parser = _parser() + args = parser.parse_args() + + config = configparser.ConfigParser() + if args.config: + config.read_file(args.config) + else: + config.read([os.path.join(os.path.abspath(__file__), "dns-sync.conf"), "/etc/dns-sync.conf"]) + #print(config) + #print(config.get("DEFAULT", "api-key")) + #print(config.has_section("DEFAULT"), config.has_option("DEFAULT", "api-key")) + + if args.api_key: + config["DEFAULT"]["api-key"] = args.api_key + + if not config.has_option("DEFAULT", "api-key"): + print("Error: Could not find api-key (not present in config under [DEFAULT]; not given via command line)", file=sys.stderr) + sys.exit(2) + + s = requests.Session() + s.headers = { + 'X-API-Key': config.get("DEFAULT", "api-key"), + 'Accept': 'application/json' + } + + domains = [] + rzone4 = [] + rzone6 = [] + usedNameservers = [] + + # assenble domain data + # dn. + qs = Domain.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("name") + getDomainsFromQueryset(qs, domains, domains, usedNameservers) + + # reverse zones + qs = ReverseZone.objects.annotate(nsCount=Count('nameservers')).filter(nsCount__gt=0).order_by("parentNet__address") + qs4 = filter(lambda _revz: _revz.getNetwork().version == 4, qs) + qs6 = filter(lambda _revz: _revz.getNetwork().version == 6, qs) + getDomainsFromQueryset(qs4, rzone4, domains, usedNameservers, v4reverse=True) + getDomainsFromQueryset(qs6, rzone6, domains, usedNameservers) + + #print("dn.", domains) + #print("v4", rzone4) + #print("v6", rzone6) + + mergeDomainsWithPdns(s, args, "dn.", domains) + mergeDomainsWithPdns(s, args, "10.in-addr.arpa.", rzone4) + mergeDomainsWithPdns(s, args, "3.2.7.c.3.a.d.f.ip6.arpa.", rzone6) if __name__ == '__main__': - main() + main() diff --git a/bin/import-data b/bin/import-data index f2ab8ea..f30ecd2 100755 --- a/bin/import-data +++ b/bin/import-data @@ -24,107 +24,107 @@ from whoisdb.models import ASBlock, ASNumber, Contact, Maintainer, InetNum __VERSION__ = '0.1' def _parser(): - parser = argparse.ArgumentParser( - #prog='foo', - #description='do some awesome foo', - ) + parser = argparse.ArgumentParser( + #prog='foo', + #description='do some awesome foo', + ) - #parser.add_argument("-p", "--port", default=2323, type=int, help="Your port") - #parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose") - parser.add_argument("-j", "--json", type=argparse.FileType('r'), required=True, help="Path to json file") + #parser.add_argument("-p", "--port", default=2323, type=int, help="Your port") + #parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose") + parser.add_argument("-j", "--json", type=argparse.FileType('r'), required=True, help="Path to json file") - parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) + parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) - return parser + return parser def main(): - parser = _parser() - args = parser.parse_args() - - defContact = Contact.objects.get(handle="UNKNOWN-DN") - defMnt = Maintainer.objects.get(handle="DARKNET-MNT") - blocks = [ - ASBlock.objects.get(handle="TRA1-ASB"), - ASBlock.objects.get(handle="UAB1-ASB") - ] - ranges = [ - InetNum.objects.get(handle="TRA1-NET"), - InetNum.objects.get(handle="DEF4-NET"), - InetNum.objects.get(handle="DEF6-NET"), - InetNum.objects.get(handle="MISC6-NET"), - InetNum.objects.get(handle="LTRA1-NET"), - InetNum.objects.get(handle="MAIN4-NET"), - ] - - - data = json.load(args.json) - print(data.keys()) - for k, v in data["handles"].items(): - print(k, v["person"]) - for asn in data["as"]: - print(asn) - if ASNumber.objects.filter(number=asn["number"]).count() > 0: - continue - - obj = ASNumber(number=asn["number"]) - block = None - for block in blocks: - if obj.number >= block.asBegin and obj.number <= block.asEnd: - obj.asblock = block - break - else: - raise ValueError("AS %d does not fit a block" % asn["number"]) - - if len(asn['admin_c']) >= 1: - name = data["handles"][asn["admin_c"][0]]["person"] - obj.name = "Imported AS of %s" % name - obj.handle = ASNumber.genGenericHandle(re.sub("[^a-zA-Z0-9 ]", "", name)) - else: - obj.name = "Imported AS without admin info" - obj.handle = ASNumber.genGenericHandle("Unknown Imported AS") - obj.description = "Object has been imported from old DB and has not yet been edited" - obj.save() - obj.mnt_by.add(defMnt) - obj.admin_c.add(defContact) - obj.save() - - for net in data["network"]: - print(net) - network = ipaddress.ip_network(net["prefix"]) - - if InetNum.objects.filter(address=str(network.network_address), netmask=network.prefixlen).count() > 0: - continue - - origin = None - if net["origin"]: - origin = ASNumber.objects.get(number=net["origin"]) - obj = InetNum(address=str(network.network_address), netmask=network.prefixlen) - obj.protocol = InetNum.IPv4 if network.version == 4 else InetNum.IPv6 - - x = list(filter(lambda _x: _x['number'] == net["origin"], data["as"])) - if len(x) > 0 and x[0]["admin_c"]: - name = data["handles"][x[0]["admin_c"][0]]["person"] - obj.name = "Imported Network of %s" % name - obj.handle = InetNum.genGenericHandle(re.sub("[^a-zA-Z0-9 ]", "", name)) - else: - obj.name = "Imported Network without admin info" - obj.handle = InetNum.genGenericHandle("Unknown Imported Network") - obj.description = "Object has been imported from old DB and has not yet been edited" - - for r in ranges: - if network.network_address in r.getNetwork(): - obj.parent_range = r - break - else: - raise ValueError("%s did not fit in any netblock" % network) - - obj.save() - - obj.mnt_by.add(defMnt) - obj.admin_c.add(defContact) - if origin: - obj.origin_as.add(origin) - obj.save() + parser = _parser() + args = parser.parse_args() + + defContact = Contact.objects.get(handle="UNKNOWN-DN") + defMnt = Maintainer.objects.get(handle="DARKNET-MNT") + blocks = [ + ASBlock.objects.get(handle="TRA1-ASB"), + ASBlock.objects.get(handle="UAB1-ASB") + ] + ranges = [ + InetNum.objects.get(handle="TRA1-NET"), + InetNum.objects.get(handle="DEF4-NET"), + InetNum.objects.get(handle="DEF6-NET"), + InetNum.objects.get(handle="MISC6-NET"), + InetNum.objects.get(handle="LTRA1-NET"), + InetNum.objects.get(handle="MAIN4-NET"), + ] + + + data = json.load(args.json) + print(data.keys()) + for k, v in data["handles"].items(): + print(k, v["person"]) + for asn in data["as"]: + print(asn) + if ASNumber.objects.filter(number=asn["number"]).count() > 0: + continue + + obj = ASNumber(number=asn["number"]) + block = None + for block in blocks: + if obj.number >= block.asBegin and obj.number <= block.asEnd: + obj.asblock = block + break + else: + raise ValueError("AS %d does not fit a block" % asn["number"]) + + if len(asn['admin_c']) >= 1: + name = data["handles"][asn["admin_c"][0]]["person"] + obj.name = "Imported AS of %s" % name + obj.handle = ASNumber.genGenericHandle(re.sub("[^a-zA-Z0-9 ]", "", name)) + else: + obj.name = "Imported AS without admin info" + obj.handle = ASNumber.genGenericHandle("Unknown Imported AS") + obj.description = "Object has been imported from old DB and has not yet been edited" + obj.save() + obj.mnt_by.add(defMnt) + obj.admin_c.add(defContact) + obj.save() + + for net in data["network"]: + print(net) + network = ipaddress.ip_network(net["prefix"]) + + if InetNum.objects.filter(address=str(network.network_address), netmask=network.prefixlen).count() > 0: + continue + + origin = None + if net["origin"]: + origin = ASNumber.objects.get(number=net["origin"]) + obj = InetNum(address=str(network.network_address), netmask=network.prefixlen) + obj.protocol = InetNum.IPv4 if network.version == 4 else InetNum.IPv6 + + x = list(filter(lambda _x: _x['number'] == net["origin"], data["as"])) + if len(x) > 0 and x[0]["admin_c"]: + name = data["handles"][x[0]["admin_c"][0]]["person"] + obj.name = "Imported Network of %s" % name + obj.handle = InetNum.genGenericHandle(re.sub("[^a-zA-Z0-9 ]", "", name)) + else: + obj.name = "Imported Network without admin info" + obj.handle = InetNum.genGenericHandle("Unknown Imported Network") + obj.description = "Object has been imported from old DB and has not yet been edited" + + for r in ranges: + if network.network_address in r.getNetwork(): + obj.parent_range = r + break + else: + raise ValueError("%s did not fit in any netblock" % network) + + obj.save() + + obj.mnt_by.add(defMnt) + obj.admin_c.add(defContact) + if origin: + obj.origin_as.add(origin) + obj.save() if __name__ == '__main__': - main() + main() diff --git a/bin/markdown-to-html b/bin/markdown-to-html index add89d5..186da47 100755 --- a/bin/markdown-to-html +++ b/bin/markdown-to-html @@ -12,11 +12,11 @@ import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) files = [ - ("templates/help/faq.md", "templates/help/faq.html"), + ("templates/help/faq.md", "templates/help/faq.html"), ] for srcFile, dstFile in files: - srcFile = os.path.join(BASE_DIR, srcFile) - dstFile = os.path.join(BASE_DIR, dstFile) - markdown.markdownFromFile(open(srcFile, "rb"), open(dstFile, "wb"), extensions=[TocExtension(baselevel=1, permalink=True)]) + srcFile = os.path.join(BASE_DIR, srcFile) + dstFile = os.path.join(BASE_DIR, dstFile) + markdown.markdownFromFile(open(srcFile, "rb"), open(dstFile, "wb"), extensions=[TocExtension(baselevel=1, permalink=True)]) diff --git a/bin/roa-export b/bin/roa-export index e1839ca..ba9d993 100755 --- a/bin/roa-export +++ b/bin/roa-export @@ -22,26 +22,26 @@ from whoisdb.models import ASNumber __VERSION__ = '0.1' def _parser(): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser() - parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) + parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) - return parser + return parser def main(): - parser = _parser() - parser.parse_args() + parser = _parser() + parser.parse_args() - roa = {} - for asn in ASNumber.objects.all(): - nets = [] - for net in asn.inetnum_set.all(): - nets.append(net.prefix()) + roa = {} + for asn in ASNumber.objects.all(): + nets = [] + for net in asn.inetnum_set.all(): + nets.append(net.prefix()) - if nets: - roa[asn.number] = nets + if nets: + roa[asn.number] = nets - print(json.dumps(roa)) + print(json.dumps(roa)) if __name__ == '__main__': - main() + main() diff --git a/bin/whoisd b/bin/whoisd index fce2823..657bb8e 100755 --- a/bin/whoisd +++ b/bin/whoisd @@ -24,84 +24,84 @@ log = logging.getLogger("whoisd") __VERSION__ = '0.1' class WhoisHandler(socketserver.BaseRequestHandler): - header = "% This is the DARKNET database query service.\n" \ - "% The objects should be in something like RPSL format.\n" \ - "%\n" \ - "% The DARKNET database is subject to terms and conditions.\n" \ - "% Mostly these are \"be nice\" and \"don't knowingly break things\".\n" \ - "\n" - - def handle(self): - self.request.sendall(self.header.encode()) - line = self.request.recv(1024) - line = line.split(b"\n", 2)[0].strip() - print("Request object is %s" % line) - log.info("Request by %s for %s" % (self.request.getpeername()[0], line)) - self.request.send(b"\n") - - objs = findInDatabase(line.decode()) - if len(objs) > 0: - self.request.sendall(("%% %d result%s\n" % (len(objs), "" if len(objs)==1 else "s")).encode()) - for obj in objs: - self.sendObject(obj) - else: - self.request.sendall(b"%% NOT FOUND\n\n") - - def sendObject(self, obj): - result = [ - "", - "%% Object %s (%s)" % (obj, obj.getClassName()), - "" - ] - - for field, value in getWhoisObjectFields(obj, False): - fieldName = field.lower().replace(" ", "-") + ":" - if not value: - value = "" - - if hasattr(value, "through"): - for v in value.all(): - result.append("%-16s %s" % (fieldName, v)) - else: - result.append("%-16s %s" % (fieldName, value)) - result.extend(["", ""]) - - self.request.sendall("\n".join(result).encode()) + header = "% This is the DARKNET database query service.\n" \ + "% The objects should be in something like RPSL format.\n" \ + "%\n" \ + "% The DARKNET database is subject to terms and conditions.\n" \ + "% Mostly these are \"be nice\" and \"don't knowingly break things\".\n" \ + "\n" + + def handle(self): + self.request.sendall(self.header.encode()) + line = self.request.recv(1024) + line = line.split(b"\n", 2)[0].strip() + print("Request object is %s" % line) + log.info("Request by %s for %s" % (self.request.getpeername()[0], line)) + self.request.send(b"\n") + + objs = findInDatabase(line.decode()) + if len(objs) > 0: + self.request.sendall(("%% %d result%s\n" % (len(objs), "" if len(objs)==1 else "s")).encode()) + for obj in objs: + self.sendObject(obj) + else: + self.request.sendall(b"%% NOT FOUND\n\n") + + def sendObject(self, obj): + result = [ + "", + "%% Object %s (%s)" % (obj, obj.getClassName()), + "" + ] + + for field, value in getWhoisObjectFields(obj, False): + fieldName = field.lower().replace(" ", "-") + ":" + if not value: + value = "" + + if hasattr(value, "through"): + for v in value.all(): + result.append("%-16s %s" % (fieldName, v)) + else: + result.append("%-16s %s" % (fieldName, value)) + result.extend(["", ""]) + + self.request.sendall("\n".join(result).encode()) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): - allow_reuse_address = True + allow_reuse_address = True def _parser(): - parser = argparse.ArgumentParser( - #prog='foo', - #description='do some awesome foo', - ) + parser = argparse.ArgumentParser( + #prog='foo', + #description='do some awesome foo', + ) - parser.add_argument("-p", "--port", default=43, type=int, help="whoisd port") - #parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose") + parser.add_argument("-p", "--port", default=43, type=int, help="whoisd port") + #parser.add_argument("-v", "--verbose", default=False, action="store_true", help="Be more verbose") - parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) + parser.add_argument("--version", action="version", version="%(prog)s " + __VERSION__) - return parser + return parser def main(): - parser = _parser() - args = parser.parse_args() + parser = _parser() + args = parser.parse_args() - server = ThreadedTCPServer(('', args.port), WhoisHandler) + server = ThreadedTCPServer(('', args.port), WhoisHandler) - while True: - try: - server.serve_forever() - except select.error as e: - log.exception(e) - except KeyboardInterrupt: - log.info("^c hit, quitting.") - break + while True: + try: + server.serve_forever() + except select.error as e: + log.exception(e) + except KeyboardInterrupt: + log.info("^c hit, quitting.") + break - server.server_close() + server.server_close() if __name__ == '__main__': - main() + main() diff --git a/dncore/forms.py b/dncore/forms.py index 0203530..ea4f4b4 100644 --- a/dncore/forms.py +++ b/dncore/forms.py @@ -7,6 +7,6 @@ from .models import User class CustomUserCreationForm(UserCreationForm): - class Meta: - model = User - fields = ("username",) + class Meta: + model = User + fields = ("username",) diff --git a/dncore/models.py b/dncore/models.py index 74d91a4..7ad1a31 100644 --- a/dncore/models.py +++ b/dncore/models.py @@ -7,4 +7,4 @@ from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): - pass + pass diff --git a/dncore/urls.py b/dncore/urls.py index 3138cbd..904cdc4 100644 --- a/dncore/urls.py +++ b/dncore/urls.py @@ -8,10 +8,10 @@ from django.contrib.auth import views as auth_views from . import views as dncore_views urlpatterns = [ - url(r'^$', dncore_views.dashboard, name='dashboard'), + url(r'^$', dncore_views.dashboard, name='dashboard'), - url(r'^login/$', auth_views.login, name='login'), - url(r'^register/$', dncore_views.RegisterUser.as_view(), name='register'), - url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'), - url(r'^profile/$', dncore_views.profile, name='profile'), + url(r'^login/$', auth_views.login, name='login'), + url(r'^register/$', dncore_views.RegisterUser.as_view(), name='register'), + url(r'^logout/$', auth_views.logout, {'next_page': '/'}, name='logout'), + url(r'^profile/$', dncore_views.profile, name='profile'), ] diff --git a/dncore/views.py b/dncore/views.py index aaea188..ca1ffb4 100644 --- a/dncore/views.py +++ b/dncore/views.py @@ -22,54 +22,54 @@ from .forms import CustomUserCreationForm @login_required def profile(request): - pwForm = None + pwForm = None - if request.method == "POST": - if request.POST.get("submit", None) == "pwchange": - pwForm = PasswordChangeForm(user=request.user, data=request.POST) - if pwForm.is_valid(): - pwForm.save() - auth_login(request, pwForm.user) - messages.success(request, "Password changed") + if request.method == "POST": + if request.POST.get("submit", None) == "pwchange": + pwForm = PasswordChangeForm(user=request.user, data=request.POST) + if pwForm.is_valid(): + pwForm.save() + auth_login(request, pwForm.user) + messages.success(request, "Password changed") - return HttpResponseRedirect(reverse("user:profile")) + return HttpResponseRedirect(reverse("user:profile")) - if not pwForm: - pwForm = PasswordChangeForm(user=request.user) + if not pwForm: + pwForm = PasswordChangeForm(user=request.user) - return render(request, "registration/profile.html", {'pwForm': pwForm}) + return render(request, "registration/profile.html", {'pwForm': pwForm}) @login_required def dashboard(request): - mnts = request.user.maintainer_set.all() - ownMnts = request.user.maintainer_set.filter(rir=False, lir=False).all().distinct() - # if account only has rir/lir objects, show them - if ownMnts.count() == 0: - ownMnts = mnts + mnts = request.user.maintainer_set.all() + ownMnts = request.user.maintainer_set.filter(rir=False, lir=False).all().distinct() + # if account only has rir/lir objects, show them + if ownMnts.count() == 0: + ownMnts = mnts - asns = ASNumber.objects.filter(Q(mnt_by__in=ownMnts) | Q(mnt_lower__in=ownMnts)).distinct() - inetnums = InetNum.objects.filter(Q(mnt_by__in=ownMnts) | Q(mnt_lower__in=ownMnts)).distinct() - domains = Domain.objects.filter(mnt_by__in=mnts).distinct() - rrequests = Request.objects.filter((Q(provider__in=mnts) | Q(applicant__in=mnts)) & Q(status=Request.STATE_OPEN)).distinct() + asns = ASNumber.objects.filter(Q(mnt_by__in=ownMnts) | Q(mnt_lower__in=ownMnts)).distinct() + inetnums = InetNum.objects.filter(Q(mnt_by__in=ownMnts) | Q(mnt_lower__in=ownMnts)).distinct() + domains = Domain.objects.filter(mnt_by__in=mnts).distinct() + rrequests = Request.objects.filter((Q(provider__in=mnts) | Q(applicant__in=mnts)) & Q(status=Request.STATE_OPEN)).distinct() - return render(request, "dncore/dashboard.html", {"asns": asns, "inetnums": inetnums, "domains": domains, 'rrequests': rrequests}) + return render(request, "dncore/dashboard.html", {"asns": asns, "inetnums": inetnums, "domains": domains, 'rrequests': rrequests}) def index(request): - if request.user.is_authenticated(): - return HttpResponseRedirect(reverse("dashboard")) + if request.user.is_authenticated(): + return HttpResponseRedirect(reverse("dashboard")) - return render(request, "index.html", {}) + return render(request, "index.html", {}) class RegisterUser(CreateView): - template_name = "dncore/registration.html" - form_class = CustomUserCreationForm - success_url = reverse_lazy("user:login") + template_name = "dncore/registration.html" + form_class = CustomUserCreationForm + success_url = reverse_lazy("user:login") - def form_valid(self, form): - ret = super(RegisterUser, self).form_valid(form) - messages.success(self.request, "You successfully registered as user %s and can now log in!" % form.instance.username) + def form_valid(self, form): + ret = super(RegisterUser, self).form_valid(form) + messages.success(self.request, "You successfully registered as user %s and can now log in!" % form.instance.username) - return ret + return ret diff --git a/dnmgmt/settings.py b/dnmgmt/settings.py index f2caade..9cc1bdc 100644 --- a/dnmgmt/settings.py +++ b/dnmgmt/settings.py @@ -21,7 +21,7 @@ from django.contrib import messages BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) TLD_NAMESERVERS = [ - '10.100.100.100', + '10.100.100.100', ] DATETIME_FORMAT = "Y-m-d H:i:s" @@ -42,47 +42,47 @@ ALLOWED_HOSTS = ["*"] # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'crispy_forms', - 'formtools', - 'dncore', - 'whoisdb', - 'rrequests', - 'domains', - 'api', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'crispy_forms', + 'formtools', + 'dncore', + 'whoisdb', + 'rrequests', + 'domains', + 'api', ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'dnmgmt.urls' TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, "templates/")], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [os.path.join(BASE_DIR, "templates/")], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, ] WSGI_APPLICATION = 'dnmgmt.wsgi.application' @@ -92,10 +92,10 @@ WSGI_APPLICATION = 'dnmgmt.wsgi.application' # https://docs.djangoproject.com/en/1.10/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } } @@ -103,18 +103,18 @@ DATABASES = { # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, ] @@ -139,11 +139,11 @@ USE_TZ = True STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, "cstatic") STATICFILES_DIRS = [ - os.path.join(BASE_DIR, "static"), + os.path.join(BASE_DIR, "static"), ] CRISPY_TEMPLATE_PACK = 'bootstrap3' MESSAGE_TAGS = { - messages.ERROR: 'danger', + messages.ERROR: 'danger', } AUTH_USER_MODEL = 'dncore.User' diff --git a/dnmgmt/urls.py b/dnmgmt/urls.py index 183fb92..2f1fa5c 100644 --- a/dnmgmt/urls.py +++ b/dnmgmt/urls.py @@ -30,15 +30,15 @@ import api.urls urlpatterns = [ - url(r'^$', dncore.views.index, name='index'), - url(r'^dashboard/$', dncore.views.dashboard, name='dashboard'), + url(r'^$', dncore.views.index, name='index'), + url(r'^dashboard/$', dncore.views.dashboard, name='dashboard'), url(r'^admin/', admin.site.urls), - url(r'^user/', include(dncore.urls, namespace='user')), - url(r'^whoisdb/', include(whoisdb.urls, namespace='whoisdb')), - url(r'^rrequests/', include(rrequests.urls, namespace='rrequests')), - url(r'^domains/', include(domains.urls, namespace='domains')), - url(r'^api/', include(api.urls, namespace='api')), + url(r'^user/', include(dncore.urls, namespace='user')), + url(r'^whoisdb/', include(whoisdb.urls, namespace='whoisdb')), + url(r'^rrequests/', include(rrequests.urls, namespace='rrequests')), + url(r'^domains/', include(domains.urls, namespace='domains')), + url(r'^api/', include(api.urls, namespace='api')), - url(r'^help/$', TemplateView.as_view(template_name='help/help.html'), name='help'), + url(r'^help/$', TemplateView.as_view(template_name='help/help.html'), name='help'), ] diff --git a/domains/forms.py b/domains/forms.py index 029d410..12c3ff4 100644 --- a/domains/forms.py +++ b/domains/forms.py @@ -16,228 +16,228 @@ import ipaddress class DomainForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): - class Meta: - model = Domain - fields = ['name', 'nameservers', 'mnt_by', 'admin_c'] + class Meta: + model = Domain + fields = ['name', 'nameservers', 'mnt_by', 'admin_c'] - def __init__(self, *args, **kwargs): - super(DomainForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(DomainForm, self).__init__(*args, **kwargs) - mnts = self._user.maintainer_set.all() - self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts)) + mnts = self._user.maintainer_set.all() + self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts)) - instance = getattr(self, "instance", None) - self._create = not (instance and instance.pk) + instance = getattr(self, "instance", None) + self._create = not (instance and instance.pk) - if not self._create: - self.fields['name'].disabled = True - self.fields['nameservers'].queryset |= self.instance.nameservers.all() + if not self._create: + self.fields['name'].disabled = True + self.fields['nameservers'].queryset |= self.instance.nameservers.all() - self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct() + self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct() - def clean_name(self): - name = self.cleaned_data['name'].lower() - if self._create: - if not name.endswith("."): - name += "." + def clean_name(self): + name = self.cleaned_data['name'].lower() + if self._create: + if not name.endswith("."): + name += "." - if not name.endswith("dn."): - raise forms.ValidationError("Only .dn domains can be registered at this point") + if not name.endswith("dn."): + raise forms.ValidationError("Only .dn domains can be registered at this point") - if name.count(".") > 2: - raise forms.ValidationError("No subdomains can be registered") + if name.count(".") > 2: + raise forms.ValidationError("No subdomains can be registered") - if not re.match("^[a-z0-9.-]+$", name): - raise forms.ValidationError("Only a-z, 0-9 and - are allowed inside the domain name") + if not re.match("^[a-z0-9.-]+$", name): + raise forms.ValidationError("Only a-z, 0-9 and - are allowed inside the domain name") - try: - Domain.objects.get(name=name) - raise forms.ValidationError("Domain already exists") - except Domain.DoesNotExist: - pass + try: + Domain.objects.get(name=name) + raise forms.ValidationError("Domain already exists") + except Domain.DoesNotExist: + pass - return name + return name class NameserverForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): - class Meta: - model = Nameserver - fields = ['name', 'glueIPv4', 'glueIPv6', 'mnt_by', 'admin_c'] - - help_texts = { - "glueIPv4": "Note: You can only set a glue record if the base domain of this nameserver belongs to you!" - } - - def __init__(self, *args, **kwargs): - super(NameserverForm, self).__init__(*args, **kwargs) - - instance = getattr(self, "instance", None) - self._create = not (instance and instance.pk) - - def cleanNetwork(self, glue): - ip = ipaddress.ip_address(glue) - proto = InetNum.IPv4 if ip.version == 4 else InetNum.IPv6 - nets = InetNum.objects.filter(parent_range=None, protocol=proto) - - if len(nets) == 0: - raise forms.ValidationError("No range has been registered for IPv%s in the whois interface" % ip.version) - - for net in nets: - if ip in net.getNetwork(): - break - else: - raise forms.ValidationError("Glue record address is not inside DarkNet (subnet %s)" % ", ".join(map(lambda _x: _x.prefix(), nets))) - - def clean_glueIPv4(self): - glue = self.cleaned_data['glueIPv4'] - - if glue: - self.cleanNetwork(glue) - - return glue - - def clean_glueIPv6(self): - glue = self.cleaned_data['glueIPv6'] - - if glue: - self.cleanNetwork(glue) - - return glue - - def clean_name(self): - name = self.cleaned_data['name'].lower().strip() - if not name.endswith("."): - name += "." - - # allow name to stay if it did not change - if not self._create and self.instance.name == name: - return name - - if name.count(".") <= 2: - raise forms.ValidationError("Nameserver must be inside a domain (e.g. ns1.noot.dn.)") - - mnts = self._user.maintainer_set.all() - try: - obj = Nameserver.objects.get(name=name, mnt_by__in=mnts) - if self._create or not self._create and obj.pk != self.instance.pk: - raise forms.ValidationError("You already have a nameserver with this name under your control") - except Nameserver.DoesNotExist: - pass - except Nameserver.MultipleObjectsReturned: - pass - - return name - - def clean(self): - cleaned_data = super(NameserverForm, self).clean() - - if not self.errors: - name = cleaned_data.get("name") - mntBy = cleaned_data.get("mnt_by") - zone = ".".join(name.split(".")[-3:]) - ipv4 = cleaned_data.get("glueIPv4", None) - ipv6 = cleaned_data.get("glueIPv6", None) - - if not ipv4: - ipv4 = None - if not ipv6: - ipv6 = None - - if self._create and (ipv4 or ipv6) or not self._create and not (self.instance.glueIPv4 == ipv4 and self.instance.glueIPv6 == ipv6): - mnts = self._user.maintainer_set.all() - domains = Domain.objects.filter(mnt_by__in=mnts) - found = False - for domain in domains: - if domain.name == zone: - found = True - break - - if not found: - raise forms.ValidationError("You have glue IPs set, but this domain is not under a domain you control.") - - if ipv4 or ipv6: - try: - ns = Nameserver.objects.get(Q(name=name) & (Q(glueIPv4__isnull=False) | Q(glueIPv6__isnull=False))) - if self._create or ns.pk != self.instance.pk: - nsMnts = ", ".join(n.handle for n in ns.mnt_by.all()) - - raise forms.ValidationError("Only one nameserver for this domain can have glue records and one already exists (maintained by %s)" % nsMnts) - except Nameserver.DoesNotExist: - pass - - failedMnts = set() - for ns in Nameserver.objects.filter(name=name, mnt_by__in=mntBy): - if self._create or self.instance.pk != ns.pk: - for mnt in ns.mnt_by.all(): - if mnt in mntBy: - failedMnts.add(mnt.handle) - - if len(failedMnts) > 0: - raise forms.ValidationError("The following maintainer objects already have this nameservers: %s" % ", ".join(failedMnts)) - - - return cleaned_data + class Meta: + model = Nameserver + fields = ['name', 'glueIPv4', 'glueIPv6', 'mnt_by', 'admin_c'] + + help_texts = { + "glueIPv4": "Note: You can only set a glue record if the base domain of this nameserver belongs to you!" + } + + def __init__(self, *args, **kwargs): + super(NameserverForm, self).__init__(*args, **kwargs) + + instance = getattr(self, "instance", None) + self._create = not (instance and instance.pk) + + def cleanNetwork(self, glue): + ip = ipaddress.ip_address(glue) + proto = InetNum.IPv4 if ip.version == 4 else InetNum.IPv6 + nets = InetNum.objects.filter(parent_range=None, protocol=proto) + + if len(nets) == 0: + raise forms.ValidationError("No range has been registered for IPv%s in the whois interface" % ip.version) + + for net in nets: + if ip in net.getNetwork(): + break + else: + raise forms.ValidationError("Glue record address is not inside DarkNet (subnet %s)" % ", ".join(map(lambda _x: _x.prefix(), nets))) + + def clean_glueIPv4(self): + glue = self.cleaned_data['glueIPv4'] + + if glue: + self.cleanNetwork(glue) + + return glue + + def clean_glueIPv6(self): + glue = self.cleaned_data['glueIPv6'] + + if glue: + self.cleanNetwork(glue) + + return glue + + def clean_name(self): + name = self.cleaned_data['name'].lower().strip() + if not name.endswith("."): + name += "." + + # allow name to stay if it did not change + if not self._create and self.instance.name == name: + return name + + if name.count(".") <= 2: + raise forms.ValidationError("Nameserver must be inside a domain (e.g. ns1.noot.dn.)") + + mnts = self._user.maintainer_set.all() + try: + obj = Nameserver.objects.get(name=name, mnt_by__in=mnts) + if self._create or not self._create and obj.pk != self.instance.pk: + raise forms.ValidationError("You already have a nameserver with this name under your control") + except Nameserver.DoesNotExist: + pass + except Nameserver.MultipleObjectsReturned: + pass + + return name + + def clean(self): + cleaned_data = super(NameserverForm, self).clean() + + if not self.errors: + name = cleaned_data.get("name") + mntBy = cleaned_data.get("mnt_by") + zone = ".".join(name.split(".")[-3:]) + ipv4 = cleaned_data.get("glueIPv4", None) + ipv6 = cleaned_data.get("glueIPv6", None) + + if not ipv4: + ipv4 = None + if not ipv6: + ipv6 = None + + if self._create and (ipv4 or ipv6) or not self._create and not (self.instance.glueIPv4 == ipv4 and self.instance.glueIPv6 == ipv6): + mnts = self._user.maintainer_set.all() + domains = Domain.objects.filter(mnt_by__in=mnts) + found = False + for domain in domains: + if domain.name == zone: + found = True + break + + if not found: + raise forms.ValidationError("You have glue IPs set, but this domain is not under a domain you control.") + + if ipv4 or ipv6: + try: + ns = Nameserver.objects.get(Q(name=name) & (Q(glueIPv4__isnull=False) | Q(glueIPv6__isnull=False))) + if self._create or ns.pk != self.instance.pk: + nsMnts = ", ".join(n.handle for n in ns.mnt_by.all()) + + raise forms.ValidationError("Only one nameserver for this domain can have glue records and one already exists (maintained by %s)" % nsMnts) + except Nameserver.DoesNotExist: + pass + + failedMnts = set() + for ns in Nameserver.objects.filter(name=name, mnt_by__in=mntBy): + if self._create or self.instance.pk != ns.pk: + for mnt in ns.mnt_by.all(): + if mnt in mntBy: + failedMnts.add(mnt.handle) + + if len(failedMnts) > 0: + raise forms.ValidationError("The following maintainer objects already have this nameservers: %s" % ", ".join(failedMnts)) + + + return cleaned_data class ReverseZoneForm(forms.ModelForm): - prefix = forms.CharField(validators=[IP46CIDRValidator]) + prefix = forms.CharField(validators=[IP46CIDRValidator]) - class Meta: - model = ReverseZone - fields = ['parentNet', 'nameservers'] + class Meta: + model = ReverseZone + fields = ['parentNet', 'nameservers'] - help_texts = { - "prefix": "The prefix in CIDR form for which this object is responsible", - } + help_texts = { + "prefix": "The prefix in CIDR form for which this object is responsible", + } - def __init__(self, user, *args, **kwargs): - self._user = user + def __init__(self, user, *args, **kwargs): + self._user = user - super(ReverseZoneForm, self).__init__(*args, **kwargs) + super(ReverseZoneForm, self).__init__(*args, **kwargs) - instance = getattr(self, "instance", None) - self._create = not (instance and instance.pk) + instance = getattr(self, "instance", None) + self._create = not (instance and instance.pk) - mnts = self._user.maintainer_set.all() - self.fields['parentNet'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + mnts = self._user.maintainer_set.all() + self.fields['parentNet'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts)) + self.fields['nameservers'].queryset = Nameserver.objects.filter(Q(mnt_by__in=mnts)) - if not self._create: - self.fields['prefix'].disabled = True - self.fields['nameservers'].queryset |= self.instance.nameservers.all() + if not self._create: + self.fields['prefix'].disabled = True + self.fields['nameservers'].queryset |= self.instance.nameservers.all() - self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct() + self.fields['nameservers'].queryset = self.fields['nameservers'].queryset.distinct() - def clean_prefix(self): - prefix = self.cleaned_data['prefix'] + def clean_prefix(self): + prefix = self.cleaned_data['prefix'] - net = ipaddress.ip_network(prefix) - if net.version == 6 and net.prefixlen % 4 != 0: - raise forms.ValidationError("IPv6 reverse zone prefix length has to be a multiple of 4") + net = ipaddress.ip_network(prefix) + if net.version == 6 and net.prefixlen % 4 != 0: + raise forms.ValidationError("IPv6 reverse zone prefix length has to be a multiple of 4") - return prefix + return prefix - def clean(self): - cleaned_data = super(ReverseZoneForm, self).clean() + def clean(self): + cleaned_data = super(ReverseZoneForm, self).clean() - if not self.errors: - if self._create: - net = ipaddress.ip_network(cleaned_data['prefix']) - parentNet = cleaned_data['parentNet'].getNetwork() + if not self.errors: + if self._create: + net = ipaddress.ip_network(cleaned_data['prefix']) + parentNet = cleaned_data['parentNet'].getNetwork() - if net.network_address not in parentNet: - raise forms.ValidationError("Given prefix %s is not inside of parent netblock %s" % (net, parentNet)) + if net.network_address not in parentNet: + raise forms.ValidationError("Given prefix %s is not inside of parent netblock %s" % (net, parentNet)) - # For now just check all the zones... - #zones = ReverseZone.objects.filter(parentNet=cleaned_data['parentNet']) - zones = ReverseZone.objects.all() - for zone in zones: - if net.network_address in zone.parentNet.getNetwork(): - raise forms.ValidationError("Given prefix already has a reverse zone object associated to it: %s" % zone) + # For now just check all the zones... + #zones = ReverseZone.objects.filter(parentNet=cleaned_data['parentNet']) + zones = ReverseZone.objects.all() + for zone in zones: + if net.network_address in zone.parentNet.getNetwork(): + raise forms.ValidationError("Given prefix already has a reverse zone object associated to it: %s" % zone) - self.instance.address = str(net.network_address) - self.instance.netmask = net.prefixlen + self.instance.address = str(net.network_address) + self.instance.netmask = net.prefixlen - return cleaned_data + return cleaned_data diff --git a/domains/models.py b/domains/models.py index 36d1292..fd290c1 100644 --- a/domains/models.py +++ b/domains/models.py @@ -14,138 +14,138 @@ import ipaddress class Nameserver(MntdObject): - handleSuffix = "NS" - # dns name - # ip address, if glue - # ipv4/ipv6 address? - handle = None - name = models.CharField(max_length=256) - glueIPv4 = models.GenericIPAddressField(protocol='IPv4', blank=True, null=True) - glueIPv6 = models.GenericIPAddressField(protocol='IPv6', blank=True, null=True) + handleSuffix = "NS" + # dns name + # ip address, if glue + # ipv4/ipv6 address? + handle = None + name = models.CharField(max_length=256) + glueIPv4 = models.GenericIPAddressField(protocol='IPv4', blank=True, null=True) + glueIPv6 = models.GenericIPAddressField(protocol='IPv6', blank=True, null=True) - admin_c = models.ManyToManyField(Contact) + admin_c = models.ManyToManyField(Contact) - def getPK(self): - return self.pk + def getPK(self): + return self.pk - def get_absolute_url(self): - return reverse("domains:nameserver-show", args=(self.pk,)) + def get_absolute_url(self): + return reverse("domains:nameserver-show", args=(self.pk,)) - def __str__(self): - return self.name + def __str__(self): + return self.name - def getAppName(self): - return "domains" + def getAppName(self): + return "domains" - def getNoDeleteReasons(self): - # nameservers can always be deleted - return [] + def getNoDeleteReasons(self): + # nameservers can always be deleted + return [] class Domain(MntdObject): - handle = None - handleSuffix = "DOM" - name = models.CharField(max_length=67, unique=True, db_index=True) + handle = None + handleSuffix = "DOM" + name = models.CharField(max_length=67, unique=True, db_index=True) - nameservers = models.ManyToManyField(Nameserver, blank=True) - admin_c = models.ManyToManyField(Contact) + nameservers = models.ManyToManyField(Nameserver, blank=True) + admin_c = models.ManyToManyField(Contact) - def getPK(self): - return self.name + def getPK(self): + return self.name - def getZone(self): - return self.name + def getZone(self): + return self.name - def get_absolute_url(self): - return reverse("domains:domain-show", args=(self.name,)) + def get_absolute_url(self): + return reverse("domains:domain-show", args=(self.name,)) - def __str__(self): - return self.name + def __str__(self): + return self.name - def getAppName(self): - return "domains" + def getAppName(self): + return "domains" - def getNoDeleteReasons(self): - reasons = [] + def getNoDeleteReasons(self): + reasons = [] - nameservers = Nameserver.objects.filter(name__endswith="." + self.name) - for ns in nameservers: - # FIXME: check if the nameserver has a glue record.... and also if it is maintained by us - reasons.append("Nameserver %s depends on this domain" % ns.name) + nameservers = Nameserver.objects.filter(name__endswith="." + self.name) + for ns in nameservers: + # FIXME: check if the nameserver has a glue record.... and also if it is maintained by us + reasons.append("Nameserver %s depends on this domain" % ns.name) - return reasons + return reasons - @classmethod - def fixName(clazz, name): - if not name.endswith("."): - name += "." - return name.lower() + @classmethod + def fixName(clazz, name): + if not name.endswith("."): + name += "." + return name.lower() class ReverseZone(WhoisObject): - handle = None - - parentNet = models.ForeignKey(InetNum) - address = models.GenericIPAddressField(db_index=True) - netmask = models.PositiveIntegerField() - - nameservers = models.ManyToManyField(Nameserver) - - def getPK(self): - return self.pk - - def prefix(self): - """ Helper function, mainly used in templates """ - return "%s/%s" % (self.address, self.netmask) - - def getNetwork(self): - return ipaddress.ip_network(self.prefix()) - - def getZone(self): - net = self.parentNet.getNetwork() - if net.version == 4: - # does not work with python3.4 - ## for these we delegate the full domain - #if 0 < net.prefixlen < 32 and net.prefixlen % 8 == 0: - # zoneParts = net.reverse_pointer.split(".") - - # return ".".join(zoneParts[1:]) - #else: - # # return RFC2317 compliant zone - # return net.reverse_pointer - parts = list(reversed(str(net.network_address).split("."))) - domain = ".".join(parts[4 - net.prefixlen // 8:]) + ".in-addr.arpa." - if net.prefixlen % 8 == 0: - # clean cut! - return domain - else: - # RFC2317 compliant! - rfc2317Domain = "%s/%s.%s" % (parts[4 - net.prefixlen // 8 - 1], net.prefixlen, domain) - return rfc2317Domain - else: - ## does not work with python3.4 - ## ipv6 - ## thefuck ipaddress lib... _the_ _fuck_ - #zoneParts = net.reverse_pointer.split(".")[-2 - net.prefixlen // 4:] - #return ".".join(zoneParts) - - parts = list(reversed(net.exploded.split("/")[0].replace(":", "")))[32 - net.prefixlen // 4:] - return ".".join(parts) + ".ip6.arpa." - - def get_absolute_url(self): - return reverse("domains:reversezone-show", args=(self.pk,)) - - def getAppName(self): - return "domains" - - def __str__(self): - return "%s @ %s" % (self.prefix(), self.parentNet) - - def getNoDeleteReasons(self): - return [] - - def canEdit(self, user): - if self.parentNet: - return self.parentNet.canEdit(user) - else: - return False + handle = None + + parentNet = models.ForeignKey(InetNum) + address = models.GenericIPAddressField(db_index=True) + netmask = models.PositiveIntegerField() + + nameservers = models.ManyToManyField(Nameserver) + + def getPK(self): + return self.pk + + def prefix(self): + """ Helper function, mainly used in templates """ + return "%s/%s" % (self.address, self.netmask) + + def getNetwork(self): + return ipaddress.ip_network(self.prefix()) + + def getZone(self): + net = self.parentNet.getNetwork() + if net.version == 4: + # does not work with python3.4 + ## for these we delegate the full domain + #if 0 < net.prefixlen < 32 and net.prefixlen % 8 == 0: + # zoneParts = net.reverse_pointer.split(".") + + # return ".".join(zoneParts[1:]) + #else: + # # return RFC2317 compliant zone + # return net.reverse_pointer + parts = list(reversed(str(net.network_address).split("."))) + domain = ".".join(parts[4 - net.prefixlen // 8:]) + ".in-addr.arpa." + if net.prefixlen % 8 == 0: + # clean cut! + return domain + else: + # RFC2317 compliant! + rfc2317Domain = "%s/%s.%s" % (parts[4 - net.prefixlen // 8 - 1], net.prefixlen, domain) + return rfc2317Domain + else: + ## does not work with python3.4 + ## ipv6 + ## thefuck ipaddress lib... _the_ _fuck_ + #zoneParts = net.reverse_pointer.split(".")[-2 - net.prefixlen // 4:] + #return ".".join(zoneParts) + + parts = list(reversed(net.exploded.split("/")[0].replace(":", "")))[32 - net.prefixlen // 4:] + return ".".join(parts) + ".ip6.arpa." + + def get_absolute_url(self): + return reverse("domains:reversezone-show", args=(self.pk,)) + + def getAppName(self): + return "domains" + + def __str__(self): + return "%s @ %s" % (self.prefix(), self.parentNet) + + def getNoDeleteReasons(self): + return [] + + def canEdit(self, user): + if self.parentNet: + return self.parentNet.canEdit(user) + else: + return False diff --git a/domains/urls.py b/domains/urls.py index ececcc7..20f1e7f 100644 --- a/domains/urls.py +++ b/domains/urls.py @@ -7,23 +7,23 @@ from django.conf.urls import url from . import views as domains_views urlpatterns = [ - url(r'^$', domains_views.overview, name='overview'), + url(r'^$', domains_views.overview, name='overview'), - url(r'domain/create/$', domains_views.DomainCreate.as_view(), name='domain-create'), - url(r'domain/check/(?P[a-z0-9.-]+)/$', domains_views.DomainCheck.as_view(), name='domain-check'), - url(r'domain/show/(?P[a-z0-9.-]+)/$', domains_views.DomainDetail.as_view(), name='domain-show'), - url(r'domain/edit/(?P[a-z0-9.-]+)/$', domains_views.DomainEdit.as_view(), name='domain-edit'), - url(r'domain/delete/(?P[a-z0-9.-]+)/$', domains_views.DomainDelete.as_view(), name='domain-delete'), + url(r'domain/create/$', domains_views.DomainCreate.as_view(), name='domain-create'), + url(r'domain/check/(?P[a-z0-9.-]+)/$', domains_views.DomainCheck.as_view(), name='domain-check'), + url(r'domain/show/(?P[a-z0-9.-]+)/$', domains_views.DomainDetail.as_view(), name='domain-show'), + url(r'domain/edit/(?P[a-z0-9.-]+)/$', domains_views.DomainEdit.as_view(), name='domain-edit'), + url(r'domain/delete/(?P[a-z0-9.-]+)/$', domains_views.DomainDelete.as_view(), name='domain-delete'), - url(r'nameserver/create/$', domains_views.NameserverCreate.as_view(), name='nameserver-create'), - url(r'nameserver/show/(?P[0-9]+)/$', domains_views.NameserverDetail.as_view(), name='nameserver-show'), - url(r'nameserver/edit/(?P[0-9]+)/$', domains_views.NameserverEdit.as_view(), name='nameserver-edit'), - url(r'nameserver/delete/(?P[0-9]+)/$', domains_views.NameserverDelete.as_view(), name='nameserver-delete'), + url(r'nameserver/create/$', domains_views.NameserverCreate.as_view(), name='nameserver-create'), + url(r'nameserver/show/(?P[0-9]+)/$', domains_views.NameserverDetail.as_view(), name='nameserver-show'), + url(r'nameserver/edit/(?P[0-9]+)/$', domains_views.NameserverEdit.as_view(), name='nameserver-edit'), + url(r'nameserver/delete/(?P[0-9]+)/$', domains_views.NameserverDelete.as_view(), name='nameserver-delete'), - url(r'reversezone/create/$', domains_views.ReverseZoneCreate.as_view(), name='reversezone-create'), - url(r'reversezone/show/(?P[0-9]+)/$', domains_views.ReverseZoneDetail.as_view(), name='reversezone-show'), - url(r'reversezone/check/(?P[0-9]+)/$', domains_views.ReverseZoneCheck.as_view(), name='reversezone-check'), - url(r'reversezone/edit/(?P[0-9]+)/$', domains_views.ReverseZoneEdit.as_view(), name='reversezone-edit'), - url(r'reversezone/delete/(?P[0-9]+)/$', domains_views.ReverseZoneDelete.as_view(), name='reversezone-delete'), + url(r'reversezone/create/$', domains_views.ReverseZoneCreate.as_view(), name='reversezone-create'), + url(r'reversezone/show/(?P[0-9]+)/$', domains_views.ReverseZoneDetail.as_view(), name='reversezone-show'), + url(r'reversezone/check/(?P[0-9]+)/$', domains_views.ReverseZoneCheck.as_view(), name='reversezone-check'), + url(r'reversezone/edit/(?P[0-9]+)/$', domains_views.ReverseZoneEdit.as_view(), name='reversezone-edit'), + url(r'reversezone/delete/(?P[0-9]+)/$', domains_views.ReverseZoneDelete.as_view(), name='reversezone-delete'), ] diff --git a/domains/views.py b/domains/views.py index 007c52c..4e08103 100644 --- a/domains/views.py +++ b/domains/views.py @@ -17,157 +17,157 @@ from .forms import DomainForm, NameserverForm, ReverseZoneForm @login_required def overview(request): - mnts = request.user.maintainer_set.all() + mnts = request.user.maintainer_set.all() - # get all domains and nameservers - domains = Domain.objects.filter(mnt_by__in=mnts).distinct() - nameservers = Nameserver.objects.filter(mnt_by__in=mnts).distinct() - reversezones = ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() + # get all domains and nameservers + domains = Domain.objects.filter(mnt_by__in=mnts).distinct() + nameservers = Nameserver.objects.filter(mnt_by__in=mnts).distinct() + reversezones = ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() - return render(request, "domains/overview.html", {"mnts": mnts, "domains": domains, "nameservers": nameservers, 'reversezones': reversezones}) + return render(request, "domains/overview.html", {"mnts": mnts, "domains": domains, "nameservers": nameservers, 'reversezones': reversezones}) class DomainCreate(LoginRequiredMixin, CreateView): - template_name = "domains/obj_create.html" - form_class = DomainForm + template_name = "domains/obj_create.html" + form_class = DomainForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(DomainCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(DomainCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - return kwargs + return kwargs class DomainCheck(LoginRequiredMixin, DetailView): - model = Domain - slug_field = "name" - slug_url_kwarg = "domain" - context_object_name = "domain" - template_name = "domains/dns_check.html" + model = Domain + slug_field = "name" + slug_url_kwarg = "domain" + context_object_name = "domain" + template_name = "domains/dns_check.html" - def get_context_data(self, **kwargs): - ctx = super(DomainCheck, self).get_context_data(**kwargs) - ctx["key"] = self.object.name - ctx["apiUrl"] = reverse("api:domain-check") + def get_context_data(self, **kwargs): + ctx = super(DomainCheck, self).get_context_data(**kwargs) + ctx["key"] = self.object.name + ctx["apiUrl"] = reverse("api:domain-check") - return ctx + return ctx class DomainDetail(LoginRequiredMixin, DetailView): - model = Domain - slug_field = "name" - slug_url_kwarg = "domain" - context_object_name = "domain" + model = Domain + slug_field = "name" + slug_url_kwarg = "domain" + context_object_name = "domain" - template_name = "whoisdb/handle_show.html" + template_name = "whoisdb/handle_show.html" class DomainEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - model = Domain - form_class = DomainForm - slug_field = "name" - slug_url_kwarg = "domain" - template_name = "domains/obj_edit.html" + model = Domain + form_class = DomainForm + slug_field = "name" + slug_url_kwarg = "domain" + template_name = "domains/obj_edit.html" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(DomainEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - return kwargs + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(DomainEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + return kwargs class DomainDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "domains/obj_delete.html" - model = Domain - slug_field = "name" - slug_url_kwarg = "domain" - success_url = reverse_lazy("domains:overview") + template_name = "domains/obj_delete.html" + model = Domain + slug_field = "name" + slug_url_kwarg = "domain" + success_url = reverse_lazy("domains:overview") class NameserverCreate(LoginRequiredMixin, CreateView): - template_name = "domains/obj_create.html" - form_class = NameserverForm + template_name = "domains/obj_create.html" + form_class = NameserverForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(NameserverCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(NameserverCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - return kwargs + return kwargs class NameserverDetail(LoginRequiredMixin, DetailView): - model = Nameserver - template_name = "whoisdb/handle_show.html" + model = Nameserver + template_name = "whoisdb/handle_show.html" class NameserverEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - model = Nameserver - form_class = NameserverForm - template_name = "domains/obj_edit.html" + model = Nameserver + form_class = NameserverForm + template_name = "domains/obj_edit.html" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(NameserverEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - return kwargs + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(NameserverEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + return kwargs class NameserverDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "domains/obj_delete.html" - model = Nameserver - success_url = reverse_lazy("domains:overview") + template_name = "domains/obj_delete.html" + model = Nameserver + success_url = reverse_lazy("domains:overview") class ReverseZoneCreate(LoginRequiredMixin, CreateView): - template_name = "domains/obj_create.html" - form_class = ReverseZoneForm + template_name = "domains/obj_create.html" + form_class = ReverseZoneForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ReverseZoneCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ReverseZoneCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - return kwargs + return kwargs class ReverseZoneCheck(LoginRequiredMixin, DetailView): - model = ReverseZone - template_name = "domains/dns_check.html" + model = ReverseZone + template_name = "domains/dns_check.html" - def get_context_data(self, **kwargs): - ctx = super(ReverseZoneCheck, self).get_context_data(**kwargs) - ctx["key"] = self.object.id - ctx["apiUrl"] = reverse("api:reversezone-check") + def get_context_data(self, **kwargs): + ctx = super(ReverseZoneCheck, self).get_context_data(**kwargs) + ctx["key"] = self.object.id + ctx["apiUrl"] = reverse("api:reversezone-check") - return ctx + return ctx class ReverseZoneDetail(LoginRequiredMixin, DetailView): - model = ReverseZone - template_name = "whoisdb/handle_show.html" + model = ReverseZone + template_name = "whoisdb/handle_show.html" class ReverseZoneEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - model = ReverseZone - form_class = ReverseZoneForm - template_name = "domains/obj_edit.html" + model = ReverseZone + form_class = ReverseZoneForm + template_name = "domains/obj_edit.html" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ReverseZoneEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ReverseZoneEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - if "initial" not in kwargs: - kwargs["initial"] = {} + if "initial" not in kwargs: + kwargs["initial"] = {} - kwargs["initial"]["prefix"] = self.object.prefix() - return kwargs + kwargs["initial"]["prefix"] = self.object.prefix() + return kwargs - def get_queryset(self): - mnts = self.request.user.maintainer_set.all() - return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() + def get_queryset(self): + mnts = self.request.user.maintainer_set.all() + return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() class ReverseZoneDelete(LoginRequiredMixin, DeleteCheckView): - template_name = "domains/obj_delete.html" - model = ReverseZone - success_url = reverse_lazy("domains:overview") + template_name = "domains/obj_delete.html" + model = ReverseZone + success_url = reverse_lazy("domains:overview") - def get_queryset(self): - mnts = self.request.user.maintainer_set.all() - return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() + def get_queryset(self): + mnts = self.request.user.maintainer_set.all() + return ReverseZone.objects.filter(Q(parentNet__mnt_by__in=mnts) | Q(parentNet__mnt_lower__in=mnts)).distinct() diff --git a/rrequests/forms.py b/rrequests/forms.py index e77ccdf..3c8aad6 100644 --- a/rrequests/forms.py +++ b/rrequests/forms.py @@ -9,51 +9,51 @@ from .models import Request from whoisdb.models import Maintainer class RequestForm(forms.Form): - RESOURCES = map(lambda _x: (_x, _x), [ - "AS Number (16bit)", "IPv4 /27", "IPv4 > /27", "IPv6", "other" - ]) + RESOURCES = map(lambda _x: (_x, _x), [ + "AS Number (16bit)", "IPv4 /27", "IPv4 > /27", "IPv6", "other" + ]) - applicant = forms.ModelChoiceField(Maintainer.objects.none(), label="Applicant (you)", help_text="Maintainer you want to request resources for") - provider = forms.ModelChoiceField(Maintainer.objects.none(), label="Provider", help_text="LIR/RIR you want to request resources from") + applicant = forms.ModelChoiceField(Maintainer.objects.none(), label="Applicant (you)", help_text="Maintainer you want to request resources for") + provider = forms.ModelChoiceField(Maintainer.objects.none(), label="Provider", help_text="LIR/RIR you want to request resources from") - subject = forms.CharField(label="Subject") - resources = forms.CheckboxSelectMultiple(choices=RESOURCES) - message = forms.CharField(widget=forms.Textarea, help_text="Describe shortly what resources you need and what you need them for") + subject = forms.CharField(label="Subject") + resources = forms.CheckboxSelectMultiple(choices=RESOURCES) + message = forms.CharField(widget=forms.Textarea, help_text="Describe shortly what resources you need and what you need them for") - def __init__(self, user, *args, **kwargs): - super(RequestForm, self).__init__(*args, **kwargs) + def __init__(self, user, *args, **kwargs): + super(RequestForm, self).__init__(*args, **kwargs) - self._user = user - self.fields['applicant'].queryset = self._user.maintainer_set.all() - self.fields['provider'].queryset = Maintainer.objects.filter(Q(rir=True) | Q(lir=True)) + self._user = user + self.fields['applicant'].queryset = self._user.maintainer_set.all() + self.fields['provider'].queryset = Maintainer.objects.filter(Q(rir=True) | Q(lir=True)) - def clean(self): - cleaned_data = super(RequestForm, self).clean() + def clean(self): + cleaned_data = super(RequestForm, self).clean() - if not self.errors: - mnts = self._user.maintainer_set.all() - if cleaned_data['applicant'] in mnts and cleaned_data['provider'] in mnts: - raise forms.ValidationError("You could request resources from yourself, but this would actually not make that much sense.") + if not self.errors: + mnts = self._user.maintainer_set.all() + if cleaned_data['applicant'] in mnts and cleaned_data['provider'] in mnts: + raise forms.ValidationError("You could request resources from yourself, but this would actually not make that much sense.") class ResponseForm(forms.Form): - new_status = forms.ChoiceField(choices=[("KEEP", "----", )] + list(Request.STATES), initial="KEEP", help_text="Only set this if you want to change the status of this request") - message = forms.CharField(widget=forms.Textarea) + new_status = forms.ChoiceField(choices=[("KEEP", "----", )] + list(Request.STATES), initial="KEEP", help_text="Only set this if you want to change the status of this request") + message = forms.CharField(widget=forms.Textarea) - def __init__(self, request, user, *args, **kwargs): - super(ResponseForm, self).__init__(*args, **kwargs) - self._request = request - self._user = user + def __init__(self, request, user, *args, **kwargs): + super(ResponseForm, self).__init__(*args, **kwargs) + self._request = request + self._user = user - def clean(self): - cleaned_data = super(ResponseForm, self).clean() + def clean(self): + cleaned_data = super(ResponseForm, self).clean() - if not self.errors: - if cleaned_data['new_status'] == self._request.status: - raise forms.ValidationError("Status changed to same as ticket") - if self._request.status in (Request.STATE_RESOLVED, Request.STATE_REJECTED) and \ - cleaned_data['new_status'] not in (Request.STATE_OPEN,): - raise forms.ValidationError("Please put this ticket in an open state before adding messages") + if not self.errors: + if cleaned_data['new_status'] == self._request.status: + raise forms.ValidationError("Status changed to same as ticket") + if self._request.status in (Request.STATE_RESOLVED, Request.STATE_REJECTED) and \ + cleaned_data['new_status'] not in (Request.STATE_OPEN,): + raise forms.ValidationError("Please put this ticket in an open state before adding messages") class ProviderResponseForm(ResponseForm): - createdResources = forms.CharField(label="Created resources", help_text="If you have created resources for this request, please enter their handles here", required=False) + createdResources = forms.CharField(label="Created resources", help_text="If you have created resources for this request, please enter their handles here", required=False) diff --git a/rrequests/models.py b/rrequests/models.py index cbb8295..04d5c72 100644 --- a/rrequests/models.py +++ b/rrequests/models.py @@ -8,49 +8,49 @@ from django.urls import reverse from whoisdb.models import Maintainer class Request(models.Model): - STATE_OPEN = "OPEN" - STATE_RESOLVED = "RESOLVED" - STATE_REJECTED = "REJECTED" - STATES = ( - (STATE_OPEN, 'Open'), - (STATE_RESOLVED, 'Resolved'), - (STATE_REJECTED, 'Rejected'), - ) + STATE_OPEN = "OPEN" + STATE_RESOLVED = "RESOLVED" + STATE_REJECTED = "REJECTED" + STATES = ( + (STATE_OPEN, 'Open'), + (STATE_RESOLVED, 'Resolved'), + (STATE_REJECTED, 'Rejected'), + ) - # request goes to mnt? - subject = models.CharField(max_length=200) + # request goes to mnt? + subject = models.CharField(max_length=200) - status = models.CharField(max_length=16, choices=STATES) + status = models.CharField(max_length=16, choices=STATES) - applicant = models.ForeignKey(Maintainer) - provider = models.ForeignKey(Maintainer, related_name='requestfrom_set') + applicant = models.ForeignKey(Maintainer) + provider = models.ForeignKey(Maintainer, related_name='requestfrom_set') - requestResources = models.TextField() - grantedResources = models.TextField() + requestResources = models.TextField() + grantedResources = models.TextField() - created = models.DateTimeField(auto_now_add=True) - lastAction = models.DateTimeField(auto_now_add=True) + created = models.DateTimeField(auto_now_add=True) + lastAction = models.DateTimeField(auto_now_add=True) - def get_absolute_url(self): - return reverse("rrequests:show", args=(self.pk,)) + def get_absolute_url(self): + return reverse("rrequests:show", args=(self.pk,)) - def __str__(self): - return "(%s -> %s) [%s] %s" % (self.applicant, self.provider, self.status, self.subject) + def __str__(self): + return "(%s -> %s) [%s] %s" % (self.applicant, self.provider, self.status, self.subject) - def getLastActionBy(self): - msgs = self.requestmessage_set.order_by("-created") + def getLastActionBy(self): + msgs = self.requestmessage_set.order_by("-created") - if msgs.count() > 0: - return msgs[0].creator - else: - return None + if msgs.count() > 0: + return msgs[0].creator + else: + return None class RequestMessage(models.Model): - request = models.ForeignKey(Request) + request = models.ForeignKey(Request) - statusChanged = models.CharField(max_length=16, choices=Request.STATES, default=None, null=True, blank=True) + statusChanged = models.CharField(max_length=16, choices=Request.STATES, default=None, null=True, blank=True) - creator = models.ForeignKey(Maintainer) - message = models.TextField() - created = models.DateTimeField(auto_now_add=True) + creator = models.ForeignKey(Maintainer) + message = models.TextField() + created = models.DateTimeField(auto_now_add=True) diff --git a/rrequests/urls.py b/rrequests/urls.py index dd29940..c0ae849 100644 --- a/rrequests/urls.py +++ b/rrequests/urls.py @@ -7,8 +7,8 @@ from django.conf.urls import url from . import views as rrequests_views urlpatterns = [ - url(r'^$', rrequests_views.listRequests, name='dashboard'), + url(r'^$', rrequests_views.listRequests, name='dashboard'), - url(r'create/$', rrequests_views.RrequestCreate.as_view(), name='create'), - url(r'show/(?P\d+)/$', rrequests_views.rrequestDetail, name='show'), + url(r'create/$', rrequests_views.RrequestCreate.as_view(), name='create'), + url(r'show/(?P\d+)/$', rrequests_views.rrequestDetail, name='show'), ] diff --git a/rrequests/views.py b/rrequests/views.py index 9d6734d..7b412eb 100644 --- a/rrequests/views.py +++ b/rrequests/views.py @@ -17,88 +17,88 @@ from .forms import RequestForm, ResponseForm, ProviderResponseForm @login_required def listRequests(request): - mnts = request.user.maintainer_set.all() - requestedFromMe = Request.objects.filter(applicant__in=mnts) - requestedToMe = Request.objects.filter(provider__in=mnts) - requests = (requestedFromMe | requestedToMe).order_by("-lastAction") + mnts = request.user.maintainer_set.all() + requestedFromMe = Request.objects.filter(applicant__in=mnts) + requestedToMe = Request.objects.filter(provider__in=mnts) + requests = (requestedFromMe | requestedToMe).order_by("-lastAction") - return render(request, "rrequests/list.html", {"mnts": mnts, "requests": requests, "requestedFromMe": requestedFromMe, "requestedToMe": requestedToMe}) + return render(request, "rrequests/list.html", {"mnts": mnts, "requests": requests, "requestedFromMe": requestedFromMe, "requestedToMe": requestedToMe}) class RrequestCreate(LoginRequiredMixin, FormView): - template_name = "rrequests/request_create.html" - form_class = RequestForm + template_name = "rrequests/request_create.html" + form_class = RequestForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(RrequestCreate, self).get_form_kwargs(*args, **kwargs) - kwargs['user'] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(RrequestCreate, self).get_form_kwargs(*args, **kwargs) + kwargs['user'] = self.request.user - return kwargs + return kwargs - def form_valid(self, form): - formData = form.cleaned_data - print(formData) - request = Request( - subject=formData['subject'], - status=Request.STATE_OPEN, - applicant=formData['applicant'], - provider=formData['provider'], - ) - request.save() + def form_valid(self, form): + formData = form.cleaned_data + print(formData) + request = Request( + subject=formData['subject'], + status=Request.STATE_OPEN, + applicant=formData['applicant'], + provider=formData['provider'], + ) + request.save() - requestMsg = RequestMessage( - request=request, + requestMsg = RequestMessage( + request=request, - creator=formData['applicant'], - message=formData['message'], - ) - requestMsg.save() + creator=formData['applicant'], + message=formData['message'], + ) + requestMsg.save() - return HttpResponseRedirect(request.get_absolute_url()) + return HttpResponseRedirect(request.get_absolute_url()) @login_required def rrequestDetail(request, pk): - mnts = request.user.maintainer_set.all() - reqObj = get_object_or_404(Request.objects.filter(Q(provider__in=mnts) | Q(applicant__in=mnts)), pk=pk) - - mnts = request.user.maintainer_set.all() - formClass = None - provider = None - initialFormData = {} - if reqObj.provider in mnts: - provider = True - formClass = ProviderResponseForm - initialFormData["createdResources"] = reqObj.grantedResources - else: - provider = False - formClass = ResponseForm - - if request.method == "POST": - form = formClass(request=reqObj, user=request.user, data=request.POST) - if form.is_valid(): - # create message object - msg = RequestMessage( - request=reqObj, - creator=reqObj.provider if provider else reqObj.applicant, - message=form.cleaned_data['message'] - ) - if form.cleaned_data['new_status'] != "KEEP": - msg.statusChanged = form.cleaned_data['new_status'] - reqObj.status = msg.statusChanged - - msg.save() - - if "createdResources" in form.cleaned_data and \ - form.cleaned_data['createdResources'].strip() != "": - reqObj.grantedResources = form.cleaned_data["createdResources"].strip() - - reqObj.lastAction = timezone.now() - reqObj.save() - - - return HttpResponseRedirect(reverse("rrequests:show", args=(pk,))) - else: - form = formClass(request=reqObj, user=request.user, initial=initialFormData) - - return render(request, "rrequests/request_detail.html", {"request": reqObj, "form": form}) + mnts = request.user.maintainer_set.all() + reqObj = get_object_or_404(Request.objects.filter(Q(provider__in=mnts) | Q(applicant__in=mnts)), pk=pk) + + mnts = request.user.maintainer_set.all() + formClass = None + provider = None + initialFormData = {} + if reqObj.provider in mnts: + provider = True + formClass = ProviderResponseForm + initialFormData["createdResources"] = reqObj.grantedResources + else: + provider = False + formClass = ResponseForm + + if request.method == "POST": + form = formClass(request=reqObj, user=request.user, data=request.POST) + if form.is_valid(): + # create message object + msg = RequestMessage( + request=reqObj, + creator=reqObj.provider if provider else reqObj.applicant, + message=form.cleaned_data['message'] + ) + if form.cleaned_data['new_status'] != "KEEP": + msg.statusChanged = form.cleaned_data['new_status'] + reqObj.status = msg.statusChanged + + msg.save() + + if "createdResources" in form.cleaned_data and \ + form.cleaned_data['createdResources'].strip() != "": + reqObj.grantedResources = form.cleaned_data["createdResources"].strip() + + reqObj.lastAction = timezone.now() + reqObj.save() + + + return HttpResponseRedirect(reverse("rrequests:show", args=(pk,))) + else: + form = formClass(request=reqObj, user=request.user, initial=initialFormData) + + return render(request, "rrequests/request_detail.html", {"request": reqObj, "form": form}) diff --git a/whoisdb/formfields.py b/whoisdb/formfields.py index 47da0f8..bc4a254 100644 --- a/whoisdb/formfields.py +++ b/whoisdb/formfields.py @@ -6,33 +6,33 @@ from django import forms class MultiTextInput(forms.widgets.Input): - input_type = "text" - - def render(self, name, value, attrs=None): - if value is not None: - selectedOptions = [] - for val in value: - for k, v in self.choices: - if val == k: - selectedOptions.append(v) - - value = " ".join(selectedOptions) + input_type = "text" + + def render(self, name, value, attrs=None): + if value is not None: + selectedOptions = [] + for val in value: + for k, v in self.choices: + if val == k: + selectedOptions.append(v) + + value = " ".join(selectedOptions) - return super(MultiTextInput, self).render(name, value, attrs) + return super(MultiTextInput, self).render(name, value, attrs) - def value_from_datadict(self, data, files, name): - values = list(filter(bool, map(lambda _x: _x.strip(), data.get(name).split(" ")))) + def value_from_datadict(self, data, files, name): + values = list(filter(bool, map(lambda _x: _x.strip(), data.get(name).split(" ")))) - result = [] - for value in values: - # FIXME: using value here throws a weird error message at some point - # could be handled by overriding the messages in ChoiceField - # or... well, don't know - kId = value - for k, v in self.choices: - if v.lower() == value.lower(): - kId = str(k) - break - result.append(kId) + result = [] + for value in values: + # FIXME: using value here throws a weird error message at some point + # could be handled by overriding the messages in ChoiceField + # or... well, don't know + kId = value + for k, v in self.choices: + if v.lower() == value.lower(): + kId = str(k) + break + result.append(kId) - return result + return result diff --git a/whoisdb/forms.py b/whoisdb/forms.py index c1c77fb..10d77c0 100644 --- a/whoisdb/forms.py +++ b/whoisdb/forms.py @@ -15,351 +15,351 @@ import ipaddress class WhoisObjectFormMixin(object): - def __init__(self, user, *args, **kwargs): - super(WhoisObjectFormMixin, self).__init__(*args, **kwargs) - self._user = user + def __init__(self, user, *args, **kwargs): + super(WhoisObjectFormMixin, self).__init__(*args, **kwargs) + self._user = user - instance = getattr(self, 'instance', None) - if instance and instance.pk: - self._create = False - #self.fields['handle'].disabled = True - else: - self._create = True + instance = getattr(self, 'instance', None) + if instance and instance.pk: + self._create = False + #self.fields['handle'].disabled = True + else: + self._create = True - if 'handle' in self.fields: - self.fields['handle'].help_text = "Handle for this object in uppercase with a suffix of -%s" % instance.handleSuffix + if 'handle' in self.fields: + self.fields['handle'].help_text = "Handle for this object in uppercase with a suffix of -%s" % instance.handleSuffix - # only show users contacts and already present contacts - mnts = self._user.maintainer_set.all() - if 'admin_c' in self.fields: - self.fields['admin_c'].queryset = Contact.getMntQueryset(mnts, self.instance, "admin_c") + # only show users contacts and already present contacts + mnts = self._user.maintainer_set.all() + if 'admin_c' in self.fields: + self.fields['admin_c'].queryset = Contact.getMntQueryset(mnts, self.instance, "admin_c") - def clean_handle(self): - HandleValidatorWithSuffix(self.instance.handleSuffix)(self.cleaned_data['handle']) - return self.cleaned_data['handle'] + def clean_handle(self): + HandleValidatorWithSuffix(self.instance.handleSuffix)(self.cleaned_data['handle']) + return self.cleaned_data['handle'] - def clean(self): - cleaned_data = super(WhoisObjectFormMixin, self).clean() - if cleaned_data.get("handle") == "AUTO" and not self.errors: - name = cleaned_data.get("name") - if name is None: - name = self._user.username + def clean(self): + cleaned_data = super(WhoisObjectFormMixin, self).clean() + if cleaned_data.get("handle") == "AUTO" and not self.errors: + name = cleaned_data.get("name") + if name is None: + name = self._user.username - cleaned_data['handle'] = self._meta.model.genGenericHandle(name) + cleaned_data['handle'] = self._meta.model.genGenericHandle(name) - # XXX: Find a better position to update last_changed - self.instance.last_modified = timezone.now() + # XXX: Find a better position to update last_changed + self.instance.last_modified = timezone.now() - return cleaned_data + return cleaned_data class MntFormMixin(object): - protectedFields = [] + protectedFields = [] - def __init__(self, lower=False, *args, **kwargs): - super(MntFormMixin, self).__init__(*args, **kwargs) + def __init__(self, lower=False, *args, **kwargs): + super(MntFormMixin, self).__init__(*args, **kwargs) - self._editLower = lower + self._editLower = lower - if self._editLower: - for key in self.protectedFields: - self.fields[key].disabled = True + if self._editLower: + for key in self.protectedFields: + self.fields[key].disabled = True - instance = getattr(self, "instance", None) - if not hasattr(self, "_create"): - self._create = not (instance and instance.pk) + instance = getattr(self, "instance", None) + if not hasattr(self, "_create"): + self._create = not (instance and instance.pk) - mntQs = orderQueryset(Maintainer.objects.all(), Q(auth=self._user), Q(pk__in=instance.mnt_by.all()) if not self._create else None) - self.fields["mnt_by"].queryset = mntQs + mntQs = orderQueryset(Maintainer.objects.all(), Q(auth=self._user), Q(pk__in=instance.mnt_by.all()) if not self._create else None) + self.fields["mnt_by"].queryset = mntQs - if "mnt_lower" in self.fields: - self.fields["mnt_lower"].queryset = mntQs + if "mnt_lower" in self.fields: + self.fields["mnt_lower"].queryset = mntQs - def clean(self): - cleaned_data = super(MntFormMixin, self).clean() + def clean(self): + cleaned_data = super(MntFormMixin, self).clean() - if not self.errors: - if self._create: - # at least one own mnt on creation - mnts = self._user.maintainer_set.all() + if not self.errors: + if self._create: + # at least one own mnt on creation + mnts = self._user.maintainer_set.all() - for mnt in cleaned_data['mnt_by']: - if mnt in mnts: - break - else: - raise forms.ValidationError("On object creation at least one maintainer needs to be under your control") + for mnt in cleaned_data['mnt_by']: + if mnt in mnts: + break + else: + raise forms.ValidationError("On object creation at least one maintainer needs to be under your control") - if cleaned_data['mnt_by'].count() > 5 or "mnt_lower" in self.fields and cleaned_data['mnt_lower'].count() > 5: - raise forms.ValidationError("Currently only 5 MNTs per object allowed. If you need more ask @ irc/rrequest and state your use case") + if cleaned_data['mnt_by'].count() > 5 or "mnt_lower" in self.fields and cleaned_data['mnt_lower'].count() > 5: + raise forms.ValidationError("Currently only 5 MNTs per object allowed. If you need more ask @ irc/rrequest and state your use case") - return cleaned_data + return cleaned_data class MntForm(WhoisObjectFormMixin, forms.ModelForm): - class Meta: - model = Maintainer - #fields = ['handle', 'description', 'admin_c', 'auth'] - fields = ['handle', 'description', 'admin_c'] - widgets = {'auth': MultiTextInput()} + class Meta: + model = Maintainer + #fields = ['handle', 'description', 'admin_c', 'auth'] + fields = ['handle', 'description', 'admin_c'] + widgets = {'auth': MultiTextInput()} - help_texts = { - 'auth': 'Enter names of users which can edit this object (space separated; ' - 'and yes, validation is somewhat broken (values disappear on error - just reload))' - } + help_texts = { + 'auth': 'Enter names of users which can edit this object (space separated; ' + 'and yes, validation is somewhat broken (values disappear on error - just reload))' + } - def __init__(self, *args, **kwargs): - super(MntForm, self).__init__(*args, **kwargs) - print(args, kwargs) - - #if self._create: - # self.fields['auth'].text("noot") + def __init__(self, *args, **kwargs): + super(MntForm, self).__init__(*args, **kwargs) + print(args, kwargs) + + #if self._create: + # self.fields['auth'].text("noot") class MntInitialForm(MntForm): - class Meta: - model = Maintainer - fields = ['handle', 'description'] + class Meta: + model = Maintainer + fields = ['handle', 'description'] class ContactForm(WhoisObjectFormMixin, forms.ModelForm): - class Meta: - model = Contact - fields = ['handle', 'name', 'mnt_by'] + class Meta: + model = Contact + fields = ['handle', 'name', 'mnt_by'] - def __init__(self, *args, **kwargs): - super(ContactForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(ContactForm, self).__init__(*args, **kwargs) - if "mnt_by" in self.fields: - self.fields['mnt_by'].queryset = Maintainer.objects.filter(auth=self._user).distinct() + if "mnt_by" in self.fields: + self.fields['mnt_by'].queryset = Maintainer.objects.filter(auth=self._user).distinct() class ContactInitialForm(ContactForm): - class Meta: - model = Contact - fields = ['handle', 'name'] + class Meta: + model = Contact + fields = ['handle', 'name'] class InetNumForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): - prefix = forms.CharField() - protectedFields = ['protocol', 'parent_range', 'mnt_by', 'prefix'] + prefix = forms.CharField() + protectedFields = ['protocol', 'parent_range', 'mnt_by', 'prefix'] - class Meta: - model = InetNum - fields = ['handle', 'protocol', 'parent_range', 'prefix', 'name', 'description', 'origin_as', 'mnt_by', 'mnt_lower', 'admin_c'] + class Meta: + model = InetNum + fields = ['handle', 'protocol', 'parent_range', 'prefix', 'name', 'description', 'origin_as', 'mnt_by', 'mnt_lower', 'admin_c'] - def __init__(self, *args, **kwargs): - super(InetNumForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(InetNumForm, self).__init__(*args, **kwargs) - if self._editLower: - for key in self.protectedFields: - self.fields[key].disabled = True + if self._editLower: + for key in self.protectedFields: + self.fields[key].disabled = True - mnts = self._user.maintainer_set.all() - #self.fields['parent_range'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)) - #if not self._create: - # self.fields['parent_range'].queryset |= InetNum.objects.filter(pk=self.instance.pk) + mnts = self._user.maintainer_set.all() + #self.fields['parent_range'].queryset = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)) + #if not self._create: + # self.fields['parent_range'].queryset |= InetNum.objects.filter(pk=self.instance.pk) - #self.fields['parent_range'].queryset = self.fields['parent_range'].queryset.distinct() - self.fields['parent_range'].queryset = InetNum.getMntQueryset(mnts, self.instance, "parent_range") - self.fields['origin_as'].queryset = ASNumber.getMntQueryset(mnts, self.instance, "origin_as") + #self.fields['parent_range'].queryset = self.fields['parent_range'].queryset.distinct() + self.fields['parent_range'].queryset = InetNum.getMntQueryset(mnts, self.instance, "parent_range") + self.fields['origin_as'].queryset = ASNumber.getMntQueryset(mnts, self.instance, "origin_as") - def clean_prefix(self): - # make sure this is a subnet we're getting - net = self.cleaned_data['prefix'].lower() - IP46CIDRValidator(net) + def clean_prefix(self): + # make sure this is a subnet we're getting + net = self.cleaned_data['prefix'].lower() + IP46CIDRValidator(net) - try: - net = ipaddress.ip_network(net) - except ValueError as e: - raise forms.ValidationError(str(e)) + try: + net = ipaddress.ip_network(net) + except ValueError as e: + raise forms.ValidationError(str(e)) - return net + return net - def clean_parent_range(self): - parent_range = self.cleaned_data.get('parent_range', None) + def clean_parent_range(self): + parent_range = self.cleaned_data.get('parent_range', None) - # allow parent range to be unset for already present objects - if not parent_range and (self._create or not self._create and self.instance.parent_range): - raise forms.ValidationError("Parent range must be set") + # allow parent range to be unset for already present objects + if not parent_range and (self._create or not self._create and self.instance.parent_range): + raise forms.ValidationError("Parent range must be set") - if not self._create and parent_range: - # make sure we don't have circular dependencies - obj = parent_range - while obj.parent_range: - if obj.pk == self.instance.pk: - raise forms.ValidationError("No circular dependencies allowed") - obj = obj.parent_range + if not self._create and parent_range: + # make sure we don't have circular dependencies + obj = parent_range + while obj.parent_range: + if obj.pk == self.instance.pk: + raise forms.ValidationError("No circular dependencies allowed") + obj = obj.parent_range - if parent_range.origin_as.count() > 0: - raise forms.ValidationError("Parent range has origin as set") + if parent_range.origin_as.count() > 0: + raise forms.ValidationError("Parent range has origin as set") - return parent_range + return parent_range - def clean(self): - cleaned_data = super(InetNumForm, self).clean() + def clean(self): + cleaned_data = super(InetNumForm, self).clean() - if not self._editLower: - if not self.errors: - if not self._create and self.cleaned_data['origin_as']: - if self.instance.inetnum_set.count() > 0: - ranges = ", ".join(map(str, self.instance.inetnum_set.all())) - raise forms.ValidationError("You cannot set an origin as if there are already existing subranges (%s)" % (ranges)) + if not self._editLower: + if not self.errors: + if not self._create and self.cleaned_data['origin_as']: + if self.instance.inetnum_set.count() > 0: + ranges = ", ".join(map(str, self.instance.inetnum_set.all())) + raise forms.ValidationError("You cannot set an origin as if there are already existing subranges (%s)" % (ranges)) - prefix = cleaned_data['prefix'] - parent = cleaned_data['parent_range'] - if parent: - parentNet = parent.getNetwork() + prefix = cleaned_data['prefix'] + parent = cleaned_data['parent_range'] + if parent: + parentNet = parent.getNetwork() - if cleaned_data['protocol'] != parent.protocol: - raise forms.ValidationError("Protocol type for prefix must be same as parent network") + if cleaned_data['protocol'] != parent.protocol: + raise forms.ValidationError("Protocol type for prefix must be same as parent network") - # check if in parent block - if prefix.network_address not in parentNet or prefix.prefixlen < parentNet.prefixlen: - raise forms.ValidationError("Prefix must be inside parent network range") + # check if in parent block + if prefix.network_address not in parentNet or prefix.prefixlen < parentNet.prefixlen: + raise forms.ValidationError("Prefix must be inside parent network range") - # check if parent block has net that overlaps with us - for otherNet in parent.inetnum_set.all(): - if self.instance and self.instance.pk == otherNet.pk: - continue + # check if parent block has net that overlaps with us + for otherNet in parent.inetnum_set.all(): + if self.instance and self.instance.pk == otherNet.pk: + continue - if otherNet.getNetwork().overlaps(prefix): - raise forms.ValidationError("The given prefix overlaps with network %s" % otherNet.handle) + if otherNet.getNetwork().overlaps(prefix): + raise forms.ValidationError("The given prefix overlaps with network %s" % otherNet.handle) - # check if subnets to this subnet are (still) in current network - if not self._create: - for subnet in self.instance.inetnum_set.all(): - if subnet.getNetwork().network_address not in self.instance.getNetwork(): - raise forms.ValidationError("Subnet %s with %s is not in block anymore" % (subnet, subnet.getNetwork())) + # check if subnets to this subnet are (still) in current network + if not self._create: + for subnet in self.instance.inetnum_set.all(): + if subnet.getNetwork().network_address not in self.instance.getNetwork(): + raise forms.ValidationError("Subnet %s with %s is not in block anymore" % (subnet, subnet.getNetwork())) - self.instance.address = str(prefix.network_address) - self.instance.netmask = prefix.prefixlen + self.instance.address = str(prefix.network_address) + self.instance.netmask = prefix.prefixlen - return cleaned_data + return cleaned_data class ASBlockForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): - protectedFields = ['parent_block', 'asBegin', 'asEnd', 'mnt_by'] + protectedFields = ['parent_block', 'asBegin', 'asEnd', 'mnt_by'] - # FIXME: Filter blocks - class Meta: - model = ASBlock - fields = ['handle', 'parent_block', 'asBegin', 'asEnd', 'name', 'description', 'mnt_by', 'mnt_lower', 'admin_c'] + # FIXME: Filter blocks + class Meta: + model = ASBlock + fields = ['handle', 'parent_block', 'asBegin', 'asEnd', 'name', 'description', 'mnt_by', 'mnt_lower', 'admin_c'] - def __init__(self, *args, **kwargs): - super(ASBlockForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(ASBlockForm, self).__init__(*args, **kwargs) - if not self.instance or self.instance and self.instance and self.instance.parent_block: - self.fields["parent_block"].required = True - if self.instance and self.instance.pk: - self.fields["parent_block"].disabled = True + if not self.instance or self.instance and self.instance and self.instance.parent_block: + self.fields["parent_block"].required = True + if self.instance and self.instance.pk: + self.fields["parent_block"].disabled = True - mnts = self._user.maintainer_set.all() - self.fields['parent_block'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "parent_block") + mnts = self._user.maintainer_set.all() + self.fields['parent_block'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "parent_block") - def clean_parent_block(self): - parent_block = self.cleaned_data.get('parent_block', None) + def clean_parent_block(self): + parent_block = self.cleaned_data.get('parent_block', None) - # allow parent range to be unset for already present objects - if not parent_block and (self._create or not self._create and self.instance.parent_block): - raise forms.ValidationError("Parent block must be set") + # allow parent range to be unset for already present objects + if not parent_block and (self._create or not self._create and self.instance.parent_block): + raise forms.ValidationError("Parent block must be set") - if not self._create and parent_block: - # make sure we don't have circular dependencies - obj = parent_block - while obj.parent_block: - if obj.pk == self.instance.pk: - raise forms.ValidationError("No circular dependencies allowed") - obj = obj.parent_block + if not self._create and parent_block: + # make sure we don't have circular dependencies + obj = parent_block + while obj.parent_block: + if obj.pk == self.instance.pk: + raise forms.ValidationError("No circular dependencies allowed") + obj = obj.parent_block - return parent_block + return parent_block - def clean(self): - cleaned_data = super(ASBlockForm, self).clean() + def clean(self): + cleaned_data = super(ASBlockForm, self).clean() - if not self.errors: - asBegin = cleaned_data['asBegin'] - asEnd = cleaned_data['asEnd'] - parent = cleaned_data['parent_block'] - # check if somebody is already using this block + if not self.errors: + asBegin = cleaned_data['asBegin'] + asEnd = cleaned_data['asEnd'] + parent = cleaned_data['parent_block'] + # check if somebody is already using this block - # check if in range - if asBegin > asEnd: - raise forms.ValidationError("AS beginning must be smaller or equal to AS end") + # check if in range + if asBegin > asEnd: + raise forms.ValidationError("AS beginning must be smaller or equal to AS end") - if parent: - if parent.asnumber_set.count() > 0: - raise forms.ValidationError("The parent AS block is already references by following AS number objects: %s" % (", ".join(map(lambda _x: _x.handle, parent.asnumber_set.all())),)) + if parent: + if parent.asnumber_set.count() > 0: + raise forms.ValidationError("The parent AS block is already references by following AS number objects: %s" % (", ".join(map(lambda _x: _x.handle, parent.asnumber_set.all())),)) - # check if same range - if not (asBegin >= parent.asBegin and asEnd <= parent.asEnd): - raise forms.ValidationError("AS beginning and end must be inside the range of the parent AS block") + # check if same range + if not (asBegin >= parent.asBegin and asEnd <= parent.asEnd): + raise forms.ValidationError("AS beginning and end must be inside the range of the parent AS block") - if parent.asBegin == asBegin and parent.asEnd == asEnd: - raise forms.ValidationError("The range of this block cannot be the same range AS the parent AS block") + if parent.asBegin == asBegin and parent.asEnd == asEnd: + raise forms.ValidationError("The range of this block cannot be the same range AS the parent AS block") - # check for overlap with other asblocks - for block in parent.asblock_set.all(): - if self.instance and self.instance.pk and block.pk == self.instance.pk: - continue + # check for overlap with other asblocks + for block in parent.asblock_set.all(): + if self.instance and self.instance.pk and block.pk == self.instance.pk: + continue - if block.asBegin <= asBegin <= block.asEnd or block.asBegin <= asEnd <= block.asEnd or \ - asBegin <= block.asBegin <= asEnd or asBegin <= block.asEnd <= asEnd: - raise forms.ValidationError("Block overlaps with block %s" % block.handle) + if block.asBegin <= asBegin <= block.asEnd or block.asBegin <= asEnd <= block.asEnd or \ + asBegin <= block.asBegin <= asEnd or asBegin <= block.asEnd <= asEnd: + raise forms.ValidationError("Block overlaps with block %s" % block.handle) - if not self._create: - # check if subblocks are still in range - for subblock in self.instance.asblock_set.all(): - if not (asBegin <= subblock.asBegin <= asEnd and asBegin <= subblock.asEnd <= asEnd): - raise forms.ValidationError("Subblock %s (%s - %s) is not contained in this block anymore" % (subblock, subblock.asBegin, subblock.asEnd)) + if not self._create: + # check if subblocks are still in range + for subblock in self.instance.asblock_set.all(): + if not (asBegin <= subblock.asBegin <= asEnd and asBegin <= subblock.asEnd <= asEnd): + raise forms.ValidationError("Subblock %s (%s - %s) is not contained in this block anymore" % (subblock, subblock.asBegin, subblock.asEnd)) - # check if asnumbers are still in range - for asnumber in self.instance.asnumber_set.all(): - if not (asBegin <= asnumber.number <= asEnd): - raise forms.ValidationError("AS %s (%s) is not contained in this block anymore" % (asnumber, asnumber.number)) + # check if asnumbers are still in range + for asnumber in self.instance.asnumber_set.all(): + if not (asBegin <= asnumber.number <= asEnd): + raise forms.ValidationError("AS %s (%s) is not contained in this block anymore" % (asnumber, asnumber.number)) - return cleaned_data + return cleaned_data class ASNumberForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): - protectedFields = ['asblock', 'number', 'mnt_by'] + protectedFields = ['asblock', 'number', 'mnt_by'] - class Meta: - model = ASNumber - fields = ['handle', 'asblock', 'number', 'volatile', 'name', 'description', 'mnt_by', 'mnt_lower', 'admin_c'] + class Meta: + model = ASNumber + fields = ['handle', 'asblock', 'number', 'volatile', 'name', 'description', 'mnt_by', 'mnt_lower', 'admin_c'] - def __init__(self, *args, **kwargs): - super(ASNumberForm, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(ASNumberForm, self).__init__(*args, **kwargs) - if not (self.instance and self.instance.pk): - self.fields["asblock"].required = True - else: - self.fields["asblock"].disabled = True + if not (self.instance and self.instance.pk): + self.fields["asblock"].required = True + else: + self.fields["asblock"].disabled = True - mnts = self._user.maintainer_set.all() - self.fields['asblock'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "asblock") + mnts = self._user.maintainer_set.all() + self.fields['asblock'].queryset = ASBlock.getMntQueryset(mnts, self.instance, "asblock") - def clean(self): - cleaned_data = super(ASNumberForm, self).clean() + def clean(self): + cleaned_data = super(ASNumberForm, self).clean() - if not self.errors: - number = cleaned_data['number'] - block = cleaned_data['asblock'] + if not self.errors: + number = cleaned_data['number'] + block = cleaned_data['asblock'] - # belongs to asblock? - if number < block.asBegin or number > block.asEnd: - raise forms.ValidationError("AS number is not inside AS block") + # belongs to asblock? + if number < block.asBegin or number > block.asEnd: + raise forms.ValidationError("AS number is not inside AS block") - # does an entry already exist? - try: - otherAS = ASNumber.objects.get(number=number) - if not (self.instance and self.instance.pk and self.instance.pk == otherAS.pk): - raise forms.ValidationError("This AS number is already represented by %s" % otherAS.handle) - except ASNumber.DoesNotExist: - pass + # does an entry already exist? + try: + otherAS = ASNumber.objects.get(number=number) + if not (self.instance and self.instance.pk and self.instance.pk == otherAS.pk): + raise forms.ValidationError("This AS number is already represented by %s" % otherAS.handle) + except ASNumber.DoesNotExist: + pass - # has already other asblock? - if block.asblock_set.count() > 0: - raise forms.ValidationError("The given AS block is already references by following sub AS blocks: %s" % (", ".join(map(lambda _x: _x.handle, block.asblock_set.all())),)) + # has already other asblock? + if block.asblock_set.count() > 0: + raise forms.ValidationError("The given AS block is already references by following sub AS blocks: %s" % (", ".join(map(lambda _x: _x.handle, block.asblock_set.all())),)) diff --git a/whoisdb/generic.py b/whoisdb/generic.py index d0e676a..f07276b 100644 --- a/whoisdb/generic.py +++ b/whoisdb/generic.py @@ -9,45 +9,45 @@ from django.db.models import Q class DeleteCheckView(DeleteView): - """ Check if object actually can be deleted. Provide reasons to template - if not. - """ - def delete(self, request, *args, **kwargs): - self.object = self.get_object() - success_url = self.get_success_url() - - reasons = self.object.getNoDeleteReasons() - if reasons: - # do not delete, do what get does... - return self.get(request, *args, **kwargs) - else: - self.object.delete() - messages.info(request, "Object %s has been deleted" % str(self.object)) - return HttpResponseRedirect(success_url) - - def get_context_data(self, **kwargs): - if 'reasons' not in kwargs: - kwargs['reasons'] = self.object.getNoDeleteReasons() - return super(DeleteCheckView, self).get_context_data(**kwargs) + """ Check if object actually can be deleted. Provide reasons to template + if not. + """ + def delete(self, request, *args, **kwargs): + self.object = self.get_object() + success_url = self.get_success_url() + + reasons = self.object.getNoDeleteReasons() + if reasons: + # do not delete, do what get does... + return self.get(request, *args, **kwargs) + else: + self.object.delete() + messages.info(request, "Object %s has been deleted" % str(self.object)) + return HttpResponseRedirect(success_url) + + def get_context_data(self, **kwargs): + if 'reasons' not in kwargs: + kwargs['reasons'] = self.object.getNoDeleteReasons() + return super(DeleteCheckView, self).get_context_data(**kwargs) class MntGenericMixin(object): - def get_queryset(self): - mnts = self.request.user.maintainer_set.all() + def get_queryset(self): + mnts = self.request.user.maintainer_set.all() - q = Q(mnt_by__in=mnts) - if hasattr(self.model, "mnt_lower"): - q |= Q(mnt_lower__in=mnts) + q = Q(mnt_by__in=mnts) + if hasattr(self.model, "mnt_lower"): + q |= Q(mnt_lower__in=mnts) - return self.model.objects.filter(q).distinct() + return self.model.objects.filter(q).distinct() - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(MntGenericMixin, self).get_form_kwargs(*args, **kwargs) + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(MntGenericMixin, self).get_form_kwargs(*args, **kwargs) - if hasattr(self.model, "mnt_lower"): - mnts = self.request.user.maintainer_set.all() - if not any(mnt in self.object.mnt_by.all() for mnt in mnts): - # we are in mnt_lower - kwargs["lower"] = True + if hasattr(self.model, "mnt_lower"): + mnts = self.request.user.maintainer_set.all() + if not any(mnt in self.object.mnt_by.all() for mnt in mnts): + # we are in mnt_lower + kwargs["lower"] = True - return kwargs + return kwargs diff --git a/whoisdb/helpers.py b/whoisdb/helpers.py index c11db9d..87fde3e 100644 --- a/whoisdb/helpers.py +++ b/whoisdb/helpers.py @@ -11,161 +11,161 @@ import ipaddress import re def _addFields(fields, obj, fieldNames): - for fieldName in fieldNames: - fields.append((fieldName.capitalize().replace("_", " "), getattr(obj, fieldName))) + for fieldName in fieldNames: + fields.append((fieldName.capitalize().replace("_", " "), getattr(obj, fieldName))) def getWhoisObjectFields(obj, owner): - fields = [] - - if getattr(obj, "handle", None): - _addFields(fields, obj, ["handle"]) - - c = type(obj) - if c == whoisdb.models.Maintainer: - _addFields(fields, obj, ["description", "admin_c"]) - if owner: - _addFields(fields, obj, ["auth"]) - elif c == whoisdb.models.Contact: - _addFields(fields, obj, ["name", "mnt_by"]) - elif c == whoisdb.models.ASBlock: - _addFields(fields, obj, ["name"]) - fields.append(("AS Range", "%s - %s" % (obj.asBegin, obj.asEnd))) - _addFields(fields, obj, ["description", "parent_block", "mnt_by", "mnt_lower", "admin_c"]) - elif c == whoisdb.models.ASNumber: - _addFields(fields, obj, ["name", "number", "description", "asblock", "volatile", "mnt_by", "mnt_lower", "admin_c"]) - elif c == whoisdb.models.InetNum: - _addFields(fields, obj, ["name"]) - fields.append(("Address CIDR", obj.prefix())) - _addFields(fields, obj, ["description", "parent_range", "origin_as", "mnt_by", "mnt_lower", "admin_c"]) - elif c == domains.models.Domain: - _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c"]) - elif c == domains.models.Nameserver: - _addFields(fields, obj, ["name", "glueIPv4", "glueIPv6", "mnt_by", "admin_c"]) - elif c == domains.models.ReverseZone: - #_addFields(fields, obj, ["name"]) - fields.append(("Address CIDR", obj.prefix())) - _addFields(fields, obj, ["parentNet", "nameservers"]) - - _addFields(fields, obj, ["created", "last_modified"]) - - return fields + fields = [] + + if getattr(obj, "handle", None): + _addFields(fields, obj, ["handle"]) + + c = type(obj) + if c == whoisdb.models.Maintainer: + _addFields(fields, obj, ["description", "admin_c"]) + if owner: + _addFields(fields, obj, ["auth"]) + elif c == whoisdb.models.Contact: + _addFields(fields, obj, ["name", "mnt_by"]) + elif c == whoisdb.models.ASBlock: + _addFields(fields, obj, ["name"]) + fields.append(("AS Range", "%s - %s" % (obj.asBegin, obj.asEnd))) + _addFields(fields, obj, ["description", "parent_block", "mnt_by", "mnt_lower", "admin_c"]) + elif c == whoisdb.models.ASNumber: + _addFields(fields, obj, ["name", "number", "description", "asblock", "volatile", "mnt_by", "mnt_lower", "admin_c"]) + elif c == whoisdb.models.InetNum: + _addFields(fields, obj, ["name"]) + fields.append(("Address CIDR", obj.prefix())) + _addFields(fields, obj, ["description", "parent_range", "origin_as", "mnt_by", "mnt_lower", "admin_c"]) + elif c == domains.models.Domain: + _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c"]) + elif c == domains.models.Nameserver: + _addFields(fields, obj, ["name", "glueIPv4", "glueIPv6", "mnt_by", "admin_c"]) + elif c == domains.models.ReverseZone: + #_addFields(fields, obj, ["name"]) + fields.append(("Address CIDR", obj.prefix())) + _addFields(fields, obj, ["parentNet", "nameservers"]) + + _addFields(fields, obj, ["created", "last_modified"]) + + return fields def guessWhoisObject(self, handle): - # is it a normal handle? - pass + # is it a normal handle? + pass def findInDatabase(rawValue): - # is this an ip address? - rawValue = rawValue.strip().upper() - value = None - results = [] - - # try subnetwork - try: - value = ipaddress.ip_network(rawValue, strict=False) - except ValueError: - pass - - if value: - # ssubnet - obj = whoisdb.models.InetNum.objects.filter(address=str(value.network_address), netmask=value.prefixlen) - results.extend(obj) - - # single ip - value = None - try: - value = ipaddress.ip_address(rawValue) - except ValueError: - pass - - if value: - # NOTE: this is only for "small subnets", we could increase this... - baseaddr = None - if value.version == 4: - basenet = ipaddress.ip_network("%s/24" % value, strict=False) - baseaddr = ".".join(str(basenet).split(".")[0:3]) + "." - else: - basenet = ipaddress.ip_network("%s/56" % value.exploded, strict=False) - baseaddr = ":".join(str(basenet).split(":")[0:4])[-2] - - nets = whoisdb.models.InetNum.objects.filter(address__startswith=baseaddr).order_by("-netmask") - for net in nets: - if value in net.getNetwork(): - results.append(net) - break - - # asnumber? - m = re.match("^(?:AS)?(\d+)$", rawValue) - if m: - # asnumber! - num = int(m.group(1)) - obj = whoisdb.models.ASNumber.objects.filter(number=num) - results.extend(obj) - - # find a matching block - blocks = whoisdb.models.ASBlock.objects.filter(asBegin__lte=num, asEnd__gte=num).annotate(size=F('asEnd')-F('asBegin')).order_by('size') - if blocks.count() > 0: - results.append(blocks[0]) - - # asblocks? smallest asblock containing the range - # WHEN anotation foo... could also be done in asnumber match - # also look for number - number queries? - - # domain? - if rawValue.endswith("DN") or rawValue.endswith("DN."): - value = rawValue.lower() - if not value.endswith("."): - value += "." - - obj = domains.models.Domain.objects.filter(name=value) - results.extend(obj) - - # contact by name? - - # handlenames for Maintainer, Contact, InetNum, ASNumber, ASBlock - handleObjs = [ - whoisdb.models.Contact, - whoisdb.models.Maintainer, - whoisdb.models.InetNum, - whoisdb.models.ASBlock, - whoisdb.models.ASNumber, - ] - for handleObj in handleObjs: - obj = handleObj.objects.filter(handle=rawValue) - if not obj and len(rawValue) >= 3: - obj = handleObj.objects.filter(handle__startswith=rawValue) - results.extend(obj) - - return results + # is this an ip address? + rawValue = rawValue.strip().upper() + value = None + results = [] + + # try subnetwork + try: + value = ipaddress.ip_network(rawValue, strict=False) + except ValueError: + pass + + if value: + # ssubnet + obj = whoisdb.models.InetNum.objects.filter(address=str(value.network_address), netmask=value.prefixlen) + results.extend(obj) + + # single ip + value = None + try: + value = ipaddress.ip_address(rawValue) + except ValueError: + pass + + if value: + # NOTE: this is only for "small subnets", we could increase this... + baseaddr = None + if value.version == 4: + basenet = ipaddress.ip_network("%s/24" % value, strict=False) + baseaddr = ".".join(str(basenet).split(".")[0:3]) + "." + else: + basenet = ipaddress.ip_network("%s/56" % value.exploded, strict=False) + baseaddr = ":".join(str(basenet).split(":")[0:4])[-2] + + nets = whoisdb.models.InetNum.objects.filter(address__startswith=baseaddr).order_by("-netmask") + for net in nets: + if value in net.getNetwork(): + results.append(net) + break + + # asnumber? + m = re.match("^(?:AS)?(\d+)$", rawValue) + if m: + # asnumber! + num = int(m.group(1)) + obj = whoisdb.models.ASNumber.objects.filter(number=num) + results.extend(obj) + + # find a matching block + blocks = whoisdb.models.ASBlock.objects.filter(asBegin__lte=num, asEnd__gte=num).annotate(size=F('asEnd')-F('asBegin')).order_by('size') + if blocks.count() > 0: + results.append(blocks[0]) + + # asblocks? smallest asblock containing the range + # WHEN anotation foo... could also be done in asnumber match + # also look for number - number queries? + + # domain? + if rawValue.endswith("DN") or rawValue.endswith("DN."): + value = rawValue.lower() + if not value.endswith("."): + value += "." + + obj = domains.models.Domain.objects.filter(name=value) + results.extend(obj) + + # contact by name? + + # handlenames for Maintainer, Contact, InetNum, ASNumber, ASBlock + handleObjs = [ + whoisdb.models.Contact, + whoisdb.models.Maintainer, + whoisdb.models.InetNum, + whoisdb.models.ASBlock, + whoisdb.models.ASNumber, + ] + for handleObj in handleObjs: + obj = handleObj.objects.filter(handle=rawValue) + if not obj and len(rawValue) >= 3: + obj = handleObj.objects.filter(handle__startswith=rawValue) + results.extend(obj) + + return results def findHandleFromStr(rawValue): - handleObjs = [ - whoisdb.models.Contact, - whoisdb.models.Maintainer, - whoisdb.models.InetNum, - whoisdb.models.ASBlock, - whoisdb.models.ASNumber, - ] + handleObjs = [ + whoisdb.models.Contact, + whoisdb.models.Maintainer, + whoisdb.models.InetNum, + whoisdb.models.ASBlock, + whoisdb.models.ASNumber, + ] - for handleObj in handleObjs: - try: - return handleObj.objects.get(handle=rawValue) - except handleObj.DoesNotExist: - pass + for handleObj in handleObjs: + try: + return handleObj.objects.get(handle=rawValue) + except handleObj.DoesNotExist: + pass - return None + return None def orderQueryset(qs, userOwned, objOwned): - # when for - whens = [When(userOwned, then=2)] - if objOwned: - # add existing - whens.append(When(objOwned, then=1)) + # when for + whens = [When(userOwned, then=2)] + if objOwned: + # add existing + whens.append(When(objOwned, then=1)) - qs = qs.annotate(card=Max(Case(*whens, default=0, output_field=IntegerField()))).order_by("-card") + qs = qs.annotate(card=Max(Case(*whens, default=0, output_field=IntegerField()))).order_by("-card") - return qs + return qs diff --git a/whoisdb/models.py b/whoisdb/models.py index c0f0607..56fbc3e 100644 --- a/whoisdb/models.py +++ b/whoisdb/models.py @@ -13,269 +13,269 @@ import ipaddress class WhoisObject(models.Model): - class Meta: - abstract = True - handleSuffix = "" - - handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidator()]) - created = models.DateTimeField(auto_now_add=True) - last_modified = models.DateTimeField(auto_now_add=True) - - #def __init__(self, *args, **kwargs): - # super(WhoisObject, self).__init__(*args, **kwargs) - - # if getattr(self, "handle"): - # field = self._meta.get_field("handle") - # if HandleValidatorWithSuffix not in map(type, field.validators): - # print(self.handle, "NOOOOT") - # field.validators.append(HandleValidatorWithSuffix(self.handleSuffix)) - # else: - # print(self.handle, list(map(type, field.validators))) - - def getPK(self): - return self.handle - - def __str__(self): - return self.handle - - def getAppName(self): - return "whoisdb" - - def getClassName(self): - return self._meta.object_name - - def genHandle(self, main=None): - if not main: - main = self.name - return self.genGenericHandle(main) - - @classmethod - def genGenericHandle(clazz, main): - prefix = "" - if " " in main: - parts = main.split(" ") - prefix = "".join(map(lambda _x: _x[0], parts)) - if len(prefix) < 3 and len(parts[-1]) > 1: - prefix += parts[-1][1:4 - len(prefix)] - else: - prefix = main[0:3] - prefix = prefix.upper() - - i = 1 - handle = "%s%%d-%s" % (prefix, clazz.handleSuffix) - while True: - try: - prefix - clazz.objects.get(handle=handle % i) - i += 1 - except clazz.DoesNotExist: - break - - return handle % i - - def getNoDeleteReasons(self): - raise NotImplementedError("Delete reason checking is not implemented for this model") - - def canBeDeleted(self): - return not bool(self.getNoDeleteReasons()) - - def handleAuto(self, name=None): - if self.handle == "AUTO": - self.handle = self.genHandle(name) + class Meta: + abstract = True + handleSuffix = "" + + handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidator()]) + created = models.DateTimeField(auto_now_add=True) + last_modified = models.DateTimeField(auto_now_add=True) + + #def __init__(self, *args, **kwargs): + # super(WhoisObject, self).__init__(*args, **kwargs) + + # if getattr(self, "handle"): + # field = self._meta.get_field("handle") + # if HandleValidatorWithSuffix not in map(type, field.validators): + # print(self.handle, "NOOOOT") + # field.validators.append(HandleValidatorWithSuffix(self.handleSuffix)) + # else: + # print(self.handle, list(map(type, field.validators))) + + def getPK(self): + return self.handle + + def __str__(self): + return self.handle + + def getAppName(self): + return "whoisdb" + + def getClassName(self): + return self._meta.object_name + + def genHandle(self, main=None): + if not main: + main = self.name + return self.genGenericHandle(main) + + @classmethod + def genGenericHandle(clazz, main): + prefix = "" + if " " in main: + parts = main.split(" ") + prefix = "".join(map(lambda _x: _x[0], parts)) + if len(prefix) < 3 and len(parts[-1]) > 1: + prefix += parts[-1][1:4 - len(prefix)] + else: + prefix = main[0:3] + prefix = prefix.upper() + + i = 1 + handle = "%s%%d-%s" % (prefix, clazz.handleSuffix) + while True: + try: + prefix + clazz.objects.get(handle=handle % i) + i += 1 + except clazz.DoesNotExist: + break + + return handle % i + + def getNoDeleteReasons(self): + raise NotImplementedError("Delete reason checking is not implemented for this model") + + def canBeDeleted(self): + return not bool(self.getNoDeleteReasons()) + + def handleAuto(self, name=None): + if self.handle == "AUTO": + self.handle = self.genHandle(name) class Maintainer(WhoisObject): - handleSuffix = "MNT" + handleSuffix = "MNT" - auth = models.ManyToManyField(User) - handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidatorWithSuffix('MNT')], help_text="Must end with -MNT, eg FOO3-MNT") - description = models.CharField(max_length=64, blank=True, help_text="Short description what this maintainer is for") + auth = models.ManyToManyField(User) + handle = models.SlugField(max_length=32, unique=True, verbose_name='handle', validators=[HandleValidatorWithSuffix('MNT')], help_text="Must end with -MNT, eg FOO3-MNT") + description = models.CharField(max_length=64, blank=True, help_text="Short description what this maintainer is for") - admin_c = models.ManyToManyField("Contact", verbose_name="Administrative Contact") + admin_c = models.ManyToManyField("Contact", verbose_name="Administrative Contact") - rir = models.BooleanField(default=False) - lir = models.BooleanField(default=False) + rir = models.BooleanField(default=False) + lir = models.BooleanField(default=False) - # autoInclude = models.BooleanField(default=True) + # autoInclude = models.BooleanField(default=True) - def get_absolute_url(self): - return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) + def get_absolute_url(self): + return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) - def getNoDeleteReasons(self): - reasons = [] + def getNoDeleteReasons(self): + reasons = [] - # FIXME: Tempfix for circular dependency problem - import domains.models + # FIXME: Tempfix for circular dependency problem + import domains.models - mntables = [Contact, ASBlock, ASNumber, InetNum, domains.models.Domain, domains.models.Nameserver] - for mntable in mntables: - candidates = mntable.objects.filter(mnt_by=self).annotate(mntCount=models.Count('mnt_by')).filter(mntCount__lte=1) - for candidate in candidates: - reasons.append("Object %s would have no maintainers left." % candidate.handle) + mntables = [Contact, ASBlock, ASNumber, InetNum, domains.models.Domain, domains.models.Nameserver] + for mntable in mntables: + candidates = mntable.objects.filter(mnt_by=self).annotate(mntCount=models.Count('mnt_by')).filter(mntCount__lte=1) + for candidate in candidates: + reasons.append("Object %s would have no maintainers left." % candidate.handle) - return reasons + return reasons - def canEdit(self, user): - return user in self.auth.all() + def canEdit(self, user): + return user in self.auth.all() class MntdObject(WhoisObject): - class Meta: - abstract = True + class Meta: + abstract = True - mnt_by = models.ManyToManyField(Maintainer, help_text="You can select multiple maintainers here") + mnt_by = models.ManyToManyField(Maintainer, help_text="You can select multiple maintainers here") - def canEdit(self, user): - if not hasattr(user, "maintainer_set"): - return False + def canEdit(self, user): + if not hasattr(user, "maintainer_set"): + return False - mnts = user.maintainer_set.all() - objmnts = self.mnt_by.all() - if hasattr(self, "mnt_lower"): - objmnts |= self.mnt_lower.all() + mnts = user.maintainer_set.all() + objmnts = self.mnt_by.all() + if hasattr(self, "mnt_lower"): + objmnts |= self.mnt_lower.all() - for objmnt in objmnts: - if objmnt in mnts: - return True - return False + for objmnt in objmnts: + if objmnt in mnts: + return True + return False - @classmethod - def getMntQueryset(clazz, mnts, instance, attr=None): - mntQ = Q(mnt_by__in=mnts) - if hasattr(clazz, "mnt_lower"): - mntQ |= Q(mnt_lower__in=mnts) + @classmethod + def getMntQueryset(clazz, mnts, instance, attr=None): + mntQ = Q(mnt_by__in=mnts) + if hasattr(clazz, "mnt_lower"): + mntQ |= Q(mnt_lower__in=mnts) - qs = clazz.objects.filter(mntQ) - if attr and instance and instance.pk: - if type(instance._meta.get_field(attr)) == models.ManyToManyField: - qs |= getattr(instance, attr).all() - elif getattr(instance, attr) is not None: - qs |= clazz.objects.filter(pk=getattr(instance, attr).pk) + qs = clazz.objects.filter(mntQ) + if attr and instance and instance.pk: + if type(instance._meta.get_field(attr)) == models.ManyToManyField: + qs |= getattr(instance, attr).all() + elif getattr(instance, attr) is not None: + qs |= clazz.objects.filter(pk=getattr(instance, attr).pk) - return qs.distinct() + return qs.distinct() class Contact(MntdObject): - handleSuffix = "DN" - TYPE_PERSON = 'PERSON' - TYPE_ROLE = 'ROLE' - TYPE = (('person', TYPE_PERSON), ('role', TYPE_ROLE)) - TYPE = (('person', TYPE_PERSON),) + handleSuffix = "DN" + TYPE_PERSON = 'PERSON' + TYPE_ROLE = 'ROLE' + TYPE = (('person', TYPE_PERSON), ('role', TYPE_ROLE)) + TYPE = (('person', TYPE_PERSON),) - name = models.CharField(max_length=128) - type = models.CharField(max_length=10, choices=TYPE, default=TYPE_PERSON) + name = models.CharField(max_length=128) + type = models.CharField(max_length=10, choices=TYPE, default=TYPE_PERSON) - def get_absolute_url(self): - return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) + def get_absolute_url(self): + return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) - def getNoDeleteReasons(self): - reasons = [] + def getNoDeleteReasons(self): + reasons = [] - contactables = [Maintainer, ASBlock, ASNumber, InetNum] - for contactable in contactables: - candidates = contactable.objects.filter(admin_c=self).annotate(contactCount=models.Count('admin_c')).filter(contactCount__lte=1) - for candidate in candidates: - reasons.append("Object %s would have no contact left." % candidate.handle) + contactables = [Maintainer, ASBlock, ASNumber, InetNum] + for contactable in contactables: + candidates = contactable.objects.filter(admin_c=self).annotate(contactCount=models.Count('admin_c')).filter(contactCount__lte=1) + for candidate in candidates: + reasons.append("Object %s would have no contact left." % candidate.handle) - return reasons + return reasons class ASBlock(MntdObject): - handleSuffix = "ASB" + handleSuffix = "ASB" - parent_block = models.ForeignKey("ASBlock", models.CASCADE, null=True, blank=True, default=None) - name = models.CharField(max_length=32) - asBegin = models.PositiveIntegerField() - asEnd = models.PositiveIntegerField() - description = models.CharField(max_length=64, blank=True) - admin_c = models.ManyToManyField("Contact") + parent_block = models.ForeignKey("ASBlock", models.CASCADE, null=True, blank=True, default=None) + name = models.CharField(max_length=32) + asBegin = models.PositiveIntegerField() + asEnd = models.PositiveIntegerField() + description = models.CharField(max_length=64, blank=True) + admin_c = models.ManyToManyField("Contact") - mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True) + mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asblock_set', blank=True) - def contains(self, block): - return self.asBegin <= block.asBegin <= self.asEnd and self.asBegin <= block.asEnd <= self.asEnd + def contains(self, block): + return self.asBegin <= block.asBegin <= self.asEnd and self.asBegin <= block.asEnd <= self.asEnd - def getResource(self): - return "%s - %s" % (self.asBegin, self.asEnd) + def getResource(self): + return "%s - %s" % (self.asBegin, self.asEnd) - def get_absolute_url(self): - return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) + def get_absolute_url(self): + return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) - def getNoDeleteReasons(self): - reasons = [] + def getNoDeleteReasons(self): + reasons = [] - if self.asblock_set.count() > 0: - reasons.append("The AS block is referenced by the following other blocks: %s" % (", ".join(map(lambda _x: _x.handle, self.asblock_set.all())))) + if self.asblock_set.count() > 0: + reasons.append("The AS block is referenced by the following other blocks: %s" % (", ".join(map(lambda _x: _x.handle, self.asblock_set.all())))) - if self.asnumber_set.count() > 0: - reasons.append("The AS block is referenced by the following as numbers: %s" % (", ".join(map(lambda _x: _x.handle, self.asnumber_set.all())))) + if self.asnumber_set.count() > 0: + reasons.append("The AS block is referenced by the following as numbers: %s" % (", ".join(map(lambda _x: _x.handle, self.asnumber_set.all())))) - return reasons + return reasons class ASNumber(MntdObject): - handleSuffix = "AS" + handleSuffix = "AS" - number = models.PositiveIntegerField(unique=True, db_index=True) - volatile = models.BooleanField(default=False, help_text="Check if this AS is not going to be online 24/7 (for example on a laptop)") - asblock = models.ForeignKey(ASBlock, models.CASCADE) - name = models.CharField(max_length=32) - description = models.CharField(max_length=64, blank=True) - admin_c = models.ManyToManyField("Contact") + number = models.PositiveIntegerField(unique=True, db_index=True) + volatile = models.BooleanField(default=False, help_text="Check if this AS is not going to be online 24/7 (for example on a laptop)") + asblock = models.ForeignKey(ASBlock, models.CASCADE) + name = models.CharField(max_length=32) + description = models.CharField(max_length=64, blank=True) + admin_c = models.ManyToManyField("Contact") - mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asnumber_set', blank=True) + mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_asnumber_set', blank=True) - def get_absolute_url(self): - return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) + def get_absolute_url(self): + return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) - def getNoDeleteReasons(self): - reasons = [] + def getNoDeleteReasons(self): + reasons = [] - return reasons + return reasons - def getResource(self): - return str(self.number) + def getResource(self): + return str(self.number) class InetNum(MntdObject): - class Meta: - unique_together = ( - ("address", "netmask"), - ) + class Meta: + unique_together = ( + ("address", "netmask"), + ) - handleSuffix = "NET" + handleSuffix = "NET" - IPv4 = "ipv4" - IPv6 = "ipv6" + IPv4 = "ipv4" + IPv6 = "ipv6" - PROTO = ((IPv4, 'IPv4'), (IPv6, 'IPv6')) - protocol = models.CharField(max_length=4, choices=PROTO) - address = models.GenericIPAddressField(db_index=True) - netmask = models.PositiveIntegerField() - parent_range = models.ForeignKey("InetNum", models.CASCADE, null=True, blank=True, default=None) - name = models.CharField(max_length=64) - description = models.CharField(max_length=64, blank=True) - origin_as = models.ManyToManyField(ASNumber, blank=True) - admin_c = models.ManyToManyField("Contact") + PROTO = ((IPv4, 'IPv4'), (IPv6, 'IPv6')) + protocol = models.CharField(max_length=4, choices=PROTO) + address = models.GenericIPAddressField(db_index=True) + netmask = models.PositiveIntegerField() + parent_range = models.ForeignKey("InetNum", models.CASCADE, null=True, blank=True, default=None) + name = models.CharField(max_length=64) + description = models.CharField(max_length=64, blank=True) + origin_as = models.ManyToManyField(ASNumber, blank=True) + admin_c = models.ManyToManyField("Contact") - mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_inetnum_set', blank=True) + mnt_lower = models.ManyToManyField(Maintainer, related_name='lower_inetnum_set', blank=True) - def getResource(self): - return self.prefix() + def getResource(self): + return self.prefix() - def prefix(self): - """ Helper function, mainly used in templates """ - return "%s/%s" % (self.address, self.netmask) + def prefix(self): + """ Helper function, mainly used in templates """ + return "%s/%s" % (self.address, self.netmask) - def getNetwork(self): - return ipaddress.ip_network(self.prefix()) + def getNetwork(self): + return ipaddress.ip_network(self.prefix()) - def get_absolute_url(self): - return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) + def get_absolute_url(self): + return reverse("whoisdb:handle-detail", kwargs={"handle": self.handle}) - def getNoDeleteReasons(self): - reasons = [] - if self.inetnum_set.all().count() > 0: - reasons.append("The following networks depend on this network: %s" % ", ".join(map(lambda _x: _x.handle, self.inetnum_set.all()))) + def getNoDeleteReasons(self): + reasons = [] + if self.inetnum_set.all().count() > 0: + reasons.append("The following networks depend on this network: %s" % ", ".join(map(lambda _x: _x.handle, self.inetnum_set.all()))) - return reasons + return reasons diff --git a/whoisdb/templatetags/handletags.py b/whoisdb/templatetags/handletags.py index ecfbe69..6caa5b6 100644 --- a/whoisdb/templatetags/handletags.py +++ b/whoisdb/templatetags/handletags.py @@ -9,44 +9,44 @@ register = template.Library() @register.filter def linkObject(value): - return mark_safe('%s' % (value.get_absolute_url(), str(value))) + return mark_safe('%s' % (value.get_absolute_url(), str(value))) @register.filter def tryLinkHandle(handle): - try: - if not handle: - raise ValueError() - HandleValidator()(str(handle)) - obj = findHandleFromStr(handle) - if obj: - return linkObject(obj) - except: - pass + try: + if not handle: + raise ValueError() + HandleValidator()(str(handle)) + obj = findHandleFromStr(handle) + if obj: + return linkObject(obj) + except: + pass - return handle + return handle @register.filter def linkObjects(value): - links = [] - for obj in value: - if hasattr(obj, "get_absolute_url"): - links.append('%s' % (obj.get_absolute_url(), str(obj))) - else: - links.append(str(obj)) + links = [] + for obj in value: + if hasattr(obj, "get_absolute_url"): + links.append('%s' % (obj.get_absolute_url(), str(obj))) + else: + links.append(str(obj)) - return mark_safe(", ".join(links)) + return mark_safe(", ".join(links)) @register.filter def getFields(value, user): - owner = value.canEdit(user) + owner = value.canEdit(user) - return getWhoisObjectFields(value, owner) + return getWhoisObjectFields(value, owner) @register.filter def userCanEdit(value, user): - if hasattr(value, "canEdit"): - return value.canEdit(user) - return False + if hasattr(value, "canEdit"): + return value.canEdit(user) + return False diff --git a/whoisdb/urls.py b/whoisdb/urls.py index d331d93..6c1c4e1 100644 --- a/whoisdb/urls.py +++ b/whoisdb/urls.py @@ -7,40 +7,40 @@ from django.conf.urls import url from . import views as whoisdb_views urlpatterns = [ - url(r'^$', whoisdb_views.dbDashboard, name='dashboard'), + url(r'^$', whoisdb_views.dbDashboard, name='dashboard'), - url(r'^search/$', whoisdb_views.searchObject, name='search'), + url(r'^search/$', whoisdb_views.searchObject, name='search'), - url(r'^create/$', whoisdb_views.createObjectOverview, name='createObjectOverview'), - url(r'^handle/(?P[A-Z0-9-]+)/$', whoisdb_views.showHandle, name='showhandle'), - url(r'^handle/(?P[A-Z0-9-]+)/$', whoisdb_views.showHandle, name='handle-detail'), + url(r'^create/$', whoisdb_views.createObjectOverview, name='createObjectOverview'), + url(r'^handle/(?P[A-Z0-9-]+)/$', whoisdb_views.showHandle, name='showhandle'), + url(r'^handle/(?P[A-Z0-9-]+)/$', whoisdb_views.showHandle, name='handle-detail'), - url(r'^mnt/create/$', whoisdb_views.MaintainerCreate.as_view(), name='maintainer-create'), - url(r'^mnt/show/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerDetail.as_view(), name='maintainer-detail'), - url(r'^mnt/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerEdit.as_view(), name='maintainer-edit'), - url(r'^mnt/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerDelete.as_view(), name='maintainer-delete'), + url(r'^mnt/create/$', whoisdb_views.MaintainerCreate.as_view(), name='maintainer-create'), + url(r'^mnt/show/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerDetail.as_view(), name='maintainer-detail'), + url(r'^mnt/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerEdit.as_view(), name='maintainer-edit'), + url(r'^mnt/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.MaintainerDelete.as_view(), name='maintainer-delete'), - url(r'^contact/create/$', whoisdb_views.ContactCreate.as_view(), name='contact-create'), - url(r'^contact/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactDetail.as_view(), name='contact-detail'), - url(r'^contact/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactEdit.as_view(), name='contact-edit'), - url(r'^contact/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactDelete.as_view(), name='contact-delete'), + url(r'^contact/create/$', whoisdb_views.ContactCreate.as_view(), name='contact-create'), + url(r'^contact/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactDetail.as_view(), name='contact-detail'), + url(r'^contact/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactEdit.as_view(), name='contact-edit'), + url(r'^contact/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ContactDelete.as_view(), name='contact-delete'), - url(r'^inetnum/create/$', whoisdb_views.InetNumCreate.as_view(), name='inetnum-create'), - url(r'^inetnum/show/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumDetail.as_view(), name='inetnum-detail'), - url(r'^inetnum/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumEdit.as_view(), name='inetnum-edit'), - url(r'^inetnum/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumDelete.as_view(), name='inetnum-delete'), + url(r'^inetnum/create/$', whoisdb_views.InetNumCreate.as_view(), name='inetnum-create'), + url(r'^inetnum/show/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumDetail.as_view(), name='inetnum-detail'), + url(r'^inetnum/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumEdit.as_view(), name='inetnum-edit'), + url(r'^inetnum/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.InetNumDelete.as_view(), name='inetnum-delete'), - url(r'^asblock/create/$', whoisdb_views.ASBlockCreate.as_view(), name='asblock-create'), - url(r'^asblock/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockDetail.as_view(), name='asblock-detail'), - url(r'^asblock/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockEdit.as_view(), name='asblock-edit'), - url(r'^asblock/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockDelete.as_view(), name='asblock-delete'), + url(r'^asblock/create/$', whoisdb_views.ASBlockCreate.as_view(), name='asblock-create'), + url(r'^asblock/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockDetail.as_view(), name='asblock-detail'), + url(r'^asblock/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockEdit.as_view(), name='asblock-edit'), + url(r'^asblock/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ASBlockDelete.as_view(), name='asblock-delete'), - url(r'^asnumber/create/$', whoisdb_views.ASNumberCreate.as_view(), name='asnumber-create'), - url(r'^asnumber/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberDetail.as_view(), name='asnumber-detail'), - url(r'^asnumber/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberEdit.as_view(), name='asnumber-edit'), - url(r'^asnumber/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberDelete.as_view(), name='asnumber-delete'), + url(r'^asnumber/create/$', whoisdb_views.ASNumberCreate.as_view(), name='asnumber-create'), + url(r'^asnumber/show/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberDetail.as_view(), name='asnumber-detail'), + url(r'^asnumber/edit/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberEdit.as_view(), name='asnumber-edit'), + url(r'^asnumber/delete/(?P[A-Z0-9-]+)/$', whoisdb_views.ASNumberDelete.as_view(), name='asnumber-delete'), - url(r'^assubnetset/create/$', whoisdb_views.ASAndSubnetWizard.as_view(), name='asandsubnet-wizard'), + url(r'^assubnetset/create/$', whoisdb_views.ASAndSubnetWizard.as_view(), name='asandsubnet-wizard'), ] diff --git a/whoisdb/validators.py b/whoisdb/validators.py index 3cc9b52..bdbcbe6 100644 --- a/whoisdb/validators.py +++ b/whoisdb/validators.py @@ -14,31 +14,31 @@ import ipaddress @deconstructible class HandleValidator(validators.RegexValidator): - regex = r'^(?:[A-Z]+[0-9]*(-[A-Z]+)|AUTO)$' - message = _( - 'Enter a valid handle (all uppercase)' - ) - flags = re.ASCII if six.PY3 else 0 + regex = r'^(?:[A-Z]+[0-9]*(-[A-Z]+)|AUTO)$' + message = _( + 'Enter a valid handle (all uppercase)' + ) + flags = re.ASCII if six.PY3 else 0 @deconstructible class HandleValidatorWithSuffix(validators.RegexValidator): - flags = re.ASCII if six.PY3 else 0 + flags = re.ASCII if six.PY3 else 0 - def __init__(self, suffix): - self.regex = r'^(?:[A-Z]+[0-9]*-%s|AUTO)$' % re.escape(suffix) - self.message = _( - 'Enter a valid handle with suffix %s (all uppercase), e.g. FOO3-%s' % (suffix, suffix) - ) + def __init__(self, suffix): + self.regex = r'^(?:[A-Z]+[0-9]*-%s|AUTO)$' % re.escape(suffix) + self.message = _( + 'Enter a valid handle with suffix %s (all uppercase), e.g. FOO3-%s' % (suffix, suffix) + ) - super(HandleValidatorWithSuffix, self).__init__() + super(HandleValidatorWithSuffix, self).__init__() def IP46CIDRValidator(value): - if not re.match(r"[0-9a-fA-F:.]+/[0-9]+", value): - raise ValidationError("Address needs to be a subnet in the format of ip/prefix") + if not re.match(r"[0-9a-fA-F:.]+/[0-9]+", value): + raise ValidationError("Address needs to be a subnet in the format of ip/prefix") - try: - ipaddress.ip_network(value) - except ValueError as e: - raise ValidationError(str(e)) + try: + ipaddress.ip_network(value) + except ValueError as e: + raise ValidationError(str(e)) diff --git a/whoisdb/views.py b/whoisdb/views.py index 0cd3231..405abdd 100644 --- a/whoisdb/views.py +++ b/whoisdb/views.py @@ -20,349 +20,349 @@ from .helpers import findInDatabase @login_required def createObjectOverview(request): - mnts = request.user.maintainer_set.filter().all() - netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + mnts = request.user.maintainer_set.filter().all() + netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - return render(request, "whoisdb/create_overview.html", {"netblocks": netblocks, "asblocks": asblocks}) + return render(request, "whoisdb/create_overview.html", {"netblocks": netblocks, "asblocks": asblocks}) @login_required def dbDashboard(request): - mnts = request.user.maintainer_set.filter(rir=False, lir=False).all() - if request.GET.get("delegated", None) or mnts.count() == 0: - # if user wants to see rir/lir objects or only has rir/lir mnts, use all available mnts - mnts = request.user.maintainer_set.all() - showDelegations = True - else: - showDelegations = False - - hasDelegations = request.user.maintainer_set.filter(Q(rir=True) | Q(lir=True)).count() > 0 - - contacts = Contact.objects.filter(mnt_by__in=mnts) - netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - asnumbers = ASNumber.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() - mntForm = contactForm = None - - if mnts.count() == 0: - mntForm = contactForm = None - if request.method == "POST": - mntForm = MntInitialForm(user=request.user, data=request.POST, prefix="mnt") - contactForm = ContactInitialForm(user=request.user, data=request.POST, prefix="contact") - if mntForm.is_valid() and contactForm.is_valid(): - mnt = mntForm.save(commit=False) - mnt.handleAuto(request.user.username) - mnt.save() - - contact = contactForm.save(commit=False) - contact.handleAuto() - contact.type = Contact.TYPE_PERSON - contact.save() - contact.mnt_by.add(mnt.id) - contact.save() - - mnt.auth.add(request.user.id) - mnt.admin_c.add(contact.id) - mnt.save() - - return HttpResponseRedirect(reverse("whoisdb:dashboard")) - else: - mntForm = MntInitialForm(user=request.user, prefix="mnt", initial={'handle': 'AUTO', 'description': 'Primary maintainer of %s' % request.user.username}) - contactForm = ContactInitialForm(user=request.user, initial={'handle': 'AUTO', 'name': request.user.username.capitalize()}, prefix='contact') - - return render(request, "whoisdb/overview.html", {"mnts": mnts, "contacts": contacts, "mntForm": mntForm, "contactForm": contactForm, "netblocks": netblocks, "asblocks": asblocks, "asnumbers": asnumbers, 'hasDelegations': hasDelegations, "showDelegations": showDelegations}) + mnts = request.user.maintainer_set.filter(rir=False, lir=False).all() + if request.GET.get("delegated", None) or mnts.count() == 0: + # if user wants to see rir/lir objects or only has rir/lir mnts, use all available mnts + mnts = request.user.maintainer_set.all() + showDelegations = True + else: + showDelegations = False + + hasDelegations = request.user.maintainer_set.filter(Q(rir=True) | Q(lir=True)).count() > 0 + + contacts = Contact.objects.filter(mnt_by__in=mnts) + netblocks = InetNum.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + asblocks = ASBlock.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + asnumbers = ASNumber.objects.filter(Q(mnt_by__in=mnts) | Q(mnt_lower__in=mnts)).distinct() + mntForm = contactForm = None + + if mnts.count() == 0: + mntForm = contactForm = None + if request.method == "POST": + mntForm = MntInitialForm(user=request.user, data=request.POST, prefix="mnt") + contactForm = ContactInitialForm(user=request.user, data=request.POST, prefix="contact") + if mntForm.is_valid() and contactForm.is_valid(): + mnt = mntForm.save(commit=False) + mnt.handleAuto(request.user.username) + mnt.save() + + contact = contactForm.save(commit=False) + contact.handleAuto() + contact.type = Contact.TYPE_PERSON + contact.save() + contact.mnt_by.add(mnt.id) + contact.save() + + mnt.auth.add(request.user.id) + mnt.admin_c.add(contact.id) + mnt.save() + + return HttpResponseRedirect(reverse("whoisdb:dashboard")) + else: + mntForm = MntInitialForm(user=request.user, prefix="mnt", initial={'handle': 'AUTO', 'description': 'Primary maintainer of %s' % request.user.username}) + contactForm = ContactInitialForm(user=request.user, initial={'handle': 'AUTO', 'name': request.user.username.capitalize()}, prefix='contact') + + return render(request, "whoisdb/overview.html", {"mnts": mnts, "contacts": contacts, "mntForm": mntForm, "contactForm": contactForm, "netblocks": netblocks, "asblocks": asblocks, "asnumbers": asnumbers, 'hasDelegations': hasDelegations, "showDelegations": showDelegations}) def showHandle(request, handle): - # a) find handle - models = [Contact, Maintainer, ASBlock, ASNumber, InetNum] - obj = None + # a) find handle + models = [Contact, Maintainer, ASBlock, ASNumber, InetNum] + obj = None - for model in models: - if handle.endswith(model.handleSuffix): - obj = get_object_or_404(model, handle=handle) - break + for model in models: + if handle.endswith(model.handleSuffix): + obj = get_object_or_404(model, handle=handle) + break - if not obj: - raise Http404("Handle object not found") + if not obj: + raise Http404("Handle object not found") - return render(request, "whoisdb/handle_show.html", {"object": obj}) + return render(request, "whoisdb/handle_show.html", {"object": obj}) def searchObject(request): - results = None - term = request.GET.get("q", None) - if term: - results = findInDatabase(term) - return render(request, "whoisdb/search.html", {"results": results, "term": term}) + results = None + term = request.GET.get("q", None) + if term: + results = findInDatabase(term) + return render(request, "whoisdb/search.html", {"results": results, "term": term}) class MaintainerCreate(LoginRequiredMixin, CreateView): - template_name = "whoisdb/obj_create.html" - form_class = MntForm + template_name = "whoisdb/obj_create.html" + form_class = MntForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(MaintainerCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = { - "handle": "AUTO", - #"auth": self.request.user.username, - } + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(MaintainerCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = { + "handle": "AUTO", + #"auth": self.request.user.username, + } - return kwargs + return kwargs - def form_valid(self, form): - self.object = form.save(commit=False) - self.object.handleAuto(self.request.user.username) - self.object.save() - self.object.auth.add(self.request.user) - self.object.save() + def form_valid(self, form): + self.object = form.save(commit=False) + self.object.handleAuto(self.request.user.username) + self.object.save() + self.object.auth.add(self.request.user) + self.object.save() - return super(MaintainerCreate, self).form_valid(form) + return super(MaintainerCreate, self).form_valid(form) class MaintainerEdit(LoginRequiredMixin, UpdateView): - template_name = "whoisdb/obj_edit.html" - model = Maintainer - form_class = MntForm - slug_field = "handle" - slug_url_kwarg = "handle" + template_name = "whoisdb/obj_edit.html" + model = Maintainer + form_class = MntForm + slug_field = "handle" + slug_url_kwarg = "handle" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(MaintainerEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - return kwargs + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(MaintainerEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + return kwargs - def get_queryset(self): - return self.model.objects.filter(auth=self.request.user) + def get_queryset(self): + return self.model.objects.filter(auth=self.request.user) class MaintainerDelete(LoginRequiredMixin, DeleteCheckView): - template_name = "whoisdb/obj_delete.html" - model = Maintainer - slug_field = "handle" - slug_url_kwarg = "handle" - success_url = reverse_lazy("whoisdb:dashboard") + template_name = "whoisdb/obj_delete.html" + model = Maintainer + slug_field = "handle" + slug_url_kwarg = "handle" + success_url = reverse_lazy("whoisdb:dashboard") - def get_queryset(self): - return self.model.objects.filter(auth=self.request.user) + def get_queryset(self): + return self.model.objects.filter(auth=self.request.user) class MaintainerDetail(LoginRequiredMixin, DetailView): - template_name = "whoisdb/handle_show.html" - model = Maintainer - slug_field = "handle" - slug_url_kwarg = "handle" - #context_object_name = "mnt" + template_name = "whoisdb/handle_show.html" + model = Maintainer + slug_field = "handle" + slug_url_kwarg = "handle" + #context_object_name = "mnt" class ContactDetail(DetailView): - model = Contact - slug_field = "handle" - slug_url_kwarg = "handle" - context_object_name = "contact" + model = Contact + slug_field = "handle" + slug_url_kwarg = "handle" + context_object_name = "contact" class ContactEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - template_name = "whoisdb/obj_edit.html" - model = Contact - form_class = ContactForm - slug_field = "handle" - slug_url_kwarg = "handle" + template_name = "whoisdb/obj_edit.html" + model = Contact + form_class = ContactForm + slug_field = "handle" + slug_url_kwarg = "handle" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ContactEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - return kwargs + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ContactEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + return kwargs class ContactCreate(LoginRequiredMixin, CreateView): - template_name = "whoisdb/obj_create.html" - form_class = ContactForm + template_name = "whoisdb/obj_create.html" + form_class = ContactForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ContactCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = { - "handle": "AUTO", - "type": Contact.TYPE_PERSON - } - return kwargs + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ContactCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = { + "handle": "AUTO", + "type": Contact.TYPE_PERSON + } + return kwargs class ContactDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "whoisdb/obj_delete.html" - model = Contact - slug_field = "handle" - slug_url_kwarg = "handle" - success_url = reverse_lazy("whoisdb:dashboard") + template_name = "whoisdb/obj_delete.html" + model = Contact + slug_field = "handle" + slug_url_kwarg = "handle" + success_url = reverse_lazy("whoisdb:dashboard") # InetNum class InetNumCreate(LoginRequiredMixin, CreateView): - template_name = "whoisdb/obj_create.html" - form_class = InetNumForm + template_name = "whoisdb/obj_create.html" + form_class = InetNumForm - def get_form_kwargs(self, *args, **kwargs): - print("NOOOOOOOOOOOOOOOOOOOOOOOOOOOOT", args, kwargs) - kwargs = super(InetNumCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = { - "handle": "AUTO", - } + def get_form_kwargs(self, *args, **kwargs): + print("NOOOOOOOOOOOOOOOOOOOOOOOOOOOOT", args, kwargs) + kwargs = super(InetNumCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = { + "handle": "AUTO", + } - return kwargs + return kwargs class InetNumDetail(DetailView): - model = InetNum - slug_field = "handle" - slug_url_kwarg = "handle" - context_object_name = "inetnum" + model = InetNum + slug_field = "handle" + slug_url_kwarg = "handle" + context_object_name = "inetnum" class InetNumEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - template_name = "whoisdb/obj_edit.html" - model = InetNum - form_class = InetNumForm - slug_field = "handle" - slug_url_kwarg = "handle" + template_name = "whoisdb/obj_edit.html" + model = InetNum + form_class = InetNumForm + slug_field = "handle" + slug_url_kwarg = "handle" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(InetNumEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = {'prefix': str(self.object.getNetwork())} + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(InetNumEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = {'prefix': str(self.object.getNetwork())} - return kwargs + return kwargs class InetNumDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "whoisdb/obj_delete.html" - model = InetNum - slug_field = "handle" - slug_url_kwarg = "handle" - success_url = reverse_lazy("whoisdb:dashboard") + template_name = "whoisdb/obj_delete.html" + model = InetNum + slug_field = "handle" + slug_url_kwarg = "handle" + success_url = reverse_lazy("whoisdb:dashboard") # asblock class ASBlockCreate(LoginRequiredMixin, CreateView): - template_name = "whoisdb/obj_create.html" - form_class = ASBlockForm + template_name = "whoisdb/obj_create.html" + form_class = ASBlockForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ASBlockCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = { - "handle": "AUTO", - } + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ASBlockCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = { + "handle": "AUTO", + } - return kwargs + return kwargs class ASBlockDetail(DetailView): - model = ASBlock - slug_field = "handle" - slug_url_kwarg = "handle" - context_object_name = "asblock" + model = ASBlock + slug_field = "handle" + slug_url_kwarg = "handle" + context_object_name = "asblock" class ASBlockEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - template_name = "whoisdb/obj_edit.html" - model = ASBlock - form_class = ASBlockForm - slug_field = "handle" - slug_url_kwarg = "handle" + template_name = "whoisdb/obj_edit.html" + model = ASBlock + form_class = ASBlockForm + slug_field = "handle" + slug_url_kwarg = "handle" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ASBlockEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - #kwargs["initial"] = {'prefix': str(self.object.getNetwork())} + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ASBlockEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + #kwargs["initial"] = {'prefix': str(self.object.getNetwork())} - return kwargs + return kwargs class ASBlockDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "whoisdb/obj_delete.html" - model = ASBlock - slug_field = "handle" - slug_url_kwarg = "handle" - success_url = reverse_lazy("whoisdb:dashboard") + template_name = "whoisdb/obj_delete.html" + model = ASBlock + slug_field = "handle" + slug_url_kwarg = "handle" + success_url = reverse_lazy("whoisdb:dashboard") # asnumber class ASNumberCreate(LoginRequiredMixin, CreateView): - template_name = "whoisdb/obj_create.html" - form_class = ASNumberForm + template_name = "whoisdb/obj_create.html" + form_class = ASNumberForm - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ASNumberCreate, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user - kwargs["initial"] = { - "handle": "AUTO", - } + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ASNumberCreate, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user + kwargs["initial"] = { + "handle": "AUTO", + } - return kwargs + return kwargs class ASNumberDetail(DetailView): - model = ASNumber - slug_field = "handle" - slug_url_kwarg = "handle" - context_object_name = "asnumber" + model = ASNumber + slug_field = "handle" + slug_url_kwarg = "handle" + context_object_name = "asnumber" class ASNumberEdit(MntGenericMixin, LoginRequiredMixin, UpdateView): - template_name = "whoisdb/obj_edit.html" - model = ASNumber - form_class = ASNumberForm - slug_field = "handle" - slug_url_kwarg = "handle" + template_name = "whoisdb/obj_edit.html" + model = ASNumber + form_class = ASNumberForm + slug_field = "handle" + slug_url_kwarg = "handle" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ASNumberEdit, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ASNumberEdit, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - return kwargs + return kwargs class ASNumberDelete(MntGenericMixin, LoginRequiredMixin, DeleteCheckView): - template_name = "whoisdb/obj_delete.html" - model = ASNumber - slug_field = "handle" - slug_url_kwarg = "handle" - success_url = reverse_lazy("whoisdb:dashboard") + template_name = "whoisdb/obj_delete.html" + model = ASNumber + slug_field = "handle" + slug_url_kwarg = "handle" + success_url = reverse_lazy("whoisdb:dashboard") class ASAndSubnetWizard(LoginRequiredMixin, SessionWizardView): - form_list = [ASNumberForm, InetNumForm] - template_name = "whoisdb/wizard.html" + form_list = [ASNumberForm, InetNumForm] + template_name = "whoisdb/wizard.html" - def get_form_initial(self, step): - return {"handle": "AUTO"} + def get_form_initial(self, step): + return {"handle": "AUTO"} - def done(self, form_list, **kwargs): - fl = list(form_list) - asNum = fl[0].save() - net = fl[1].save() + def done(self, form_list, **kwargs): + fl = list(form_list) + asNum = fl[0].save() + net = fl[1].save() - messages.info(self.request, "The following objects have been created: AS %s %s, Subnet %s %s" % (asNum.handle, asNum.number, net.handle, net.getNetwork())) + messages.info(self.request, "The following objects have been created: AS %s %s, Subnet %s %s" % (asNum.handle, asNum.number, net.handle, net.getNetwork())) - return HttpResponseRedirect(reverse("whoisdb:dashboard")) + return HttpResponseRedirect(reverse("whoisdb:dashboard")) - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ASAndSubnetWizard, self).get_form_kwargs(*args, **kwargs) - kwargs["user"] = self.request.user + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ASAndSubnetWizard, self).get_form_kwargs(*args, **kwargs) + kwargs["user"] = self.request.user - return kwargs + return kwargs - def get_context_data(self, *args, **kwargs): - d = super(ASAndSubnetWizard, self).get_context_data(*args, **kwargs) + def get_context_data(self, *args, **kwargs): + d = super(ASAndSubnetWizard, self).get_context_data(*args, **kwargs) - step = d["wizard"]["steps"].step1 - if step == 1: - d["message"] = "Create an AS object" - elif step == 2: - d["message"] = "Create a Subnet" + step = d["wizard"]["steps"].step1 + if step == 1: + d["message"] = "Create an AS object" + elif step == 2: + d["message"] = "Create a Subnet" - return d + return d From ef5afbfe3a45db324466cbd823e7898e993d13a5 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 31 May 2019 00:12:20 +0200 Subject: [PATCH 3/5] Support for DS records --- bin/dns-sync | 3 ++ domains/forms.py | 35 +++++++++++++++++-- domains/migrations/0004_auto_20170403_0533.py | 25 +++++++++++++ domains/migrations/0005_domain_ds_records.py | 20 +++++++++++ domains/models.py | 3 ++ whoisdb/helpers.py | 2 +- 6 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 domains/migrations/0004_auto_20170403_0533.py create mode 100644 domains/migrations/0005_domain_ds_records.py diff --git a/bin/dns-sync b/bin/dns-sync index 67a5eb5..e71c44e 100755 --- a/bin/dns-sync +++ b/bin/dns-sync @@ -105,6 +105,9 @@ def getDomainsFromQueryset(qs, zone, glueRecords, usedNameservers, v4reverse=Fal zone.append((domain.getZone(), "NS", servers)) + if domain.ds_records: + zone.append((domain.getZone(), "DS", domain.ds_records.split("\n"))) + if v4reverse: # for ipv4 reverse we have to do some extra work in case of classless delegations # see RFC2317 diff --git a/domains/forms.py b/domains/forms.py index 12c3ff4..744a920 100644 --- a/domains/forms.py +++ b/domains/forms.py @@ -15,10 +15,41 @@ import re import ipaddress -class DomainForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): +class DSRecordMixin(object): + ds_re = re.compile(r"^(?P\d+)\s+(?P\d+)\s+(?P\d+)\s+(?P[0-9a-fA-F]+)$") + HASH_SUPPORTED = (1, 2) + CRYPTO_SUPPORTED = (3, 5, 6, 8, 10, 13, 15) + + def clean_ds_records(self): + ds_records = self.cleaned_data['ds_records'].strip() + result = [] + + if not ds_records: + return '' + + for n, rec in enumerate(ds_records.split("\n"), 1): + rec = rec.strip() + m = self.ds_re.match(rec) + if not m: + raise forms.ValidationError("Could not parse records {} - needs to be in format " + "' '".format(n)) + + if int(m.group('hashtype')) not in self.HASH_SUPPORTED: + raise forms.ValidationError("Record {} has an invalid hashtype of {}, supported are {}" + "".format(n, m.group('hashtype'), " ".join(map(str, self.HASH_SUPPORTED)))) + if int(m.group('crypto')) not in self.CRYPTO_SUPPORTED: + raise forms.ValidationError("Record {} has unsupported crypto {}, supported are {}" + "".format(n, m.group('crypto'), " ".join(map(str, self.CRYPTO_SUPPORTED)))) + + result.append("{id} {crypto} {hashtype} {hash}".format(**m.groupdict())) + + return "\n".join(result) + + +class DomainForm(MntFormMixin, WhoisObjectFormMixin, DSRecordMixin, forms.ModelForm): class Meta: model = Domain - fields = ['name', 'nameservers', 'mnt_by', 'admin_c'] + fields = ['name', 'nameservers', 'mnt_by', 'admin_c', 'ds_records'] def __init__(self, *args, **kwargs): super(DomainForm, self).__init__(*args, **kwargs) diff --git a/domains/migrations/0004_auto_20170403_0533.py b/domains/migrations/0004_auto_20170403_0533.py new file mode 100644 index 0000000..857d3aa --- /dev/null +++ b/domains/migrations/0004_auto_20170403_0533.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-04-03 05:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('domains', '0003_auto_20170322_1801'), + ] + + operations = [ + migrations.AlterField( + model_name='domain', + name='mnt_by', + field=models.ManyToManyField(help_text='You can select multiple maintainers here', to='whoisdb.Maintainer'), + ), + migrations.AlterField( + model_name='nameserver', + name='mnt_by', + field=models.ManyToManyField(help_text='You can select multiple maintainers here', to='whoisdb.Maintainer'), + ), + ] diff --git a/domains/migrations/0005_domain_ds_records.py b/domains/migrations/0005_domain_ds_records.py new file mode 100644 index 0000000..dcae33e --- /dev/null +++ b/domains/migrations/0005_domain_ds_records.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11 on 2019-05-30 21:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('domains', '0004_auto_20170403_0533'), + ] + + operations = [ + migrations.AddField( + model_name='domain', + name='ds_records', + field=models.TextField(blank=True), + ), + ] diff --git a/domains/models.py b/domains/models.py index fd290c1..16fd79a 100644 --- a/domains/models.py +++ b/domains/models.py @@ -50,6 +50,9 @@ class Domain(MntdObject): nameservers = models.ManyToManyField(Nameserver, blank=True) admin_c = models.ManyToManyField(Contact) + ds_records = models.TextField(blank=True, verbose_name='DS Records', + help_text='DS Records in the format of [id] [crypto-algo] [hash-algo] [hash]') + def getPK(self): return self.name diff --git a/whoisdb/helpers.py b/whoisdb/helpers.py index 87fde3e..55823be 100644 --- a/whoisdb/helpers.py +++ b/whoisdb/helpers.py @@ -39,7 +39,7 @@ def getWhoisObjectFields(obj, owner): fields.append(("Address CIDR", obj.prefix())) _addFields(fields, obj, ["description", "parent_range", "origin_as", "mnt_by", "mnt_lower", "admin_c"]) elif c == domains.models.Domain: - _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c"]) + _addFields(fields, obj, ["name", "nameservers", "mnt_by", "admin_c", "ds_records"]) elif c == domains.models.Nameserver: _addFields(fields, obj, ["name", "glueIPv4", "glueIPv6", "mnt_by", "admin_c"]) elif c == domains.models.ReverseZone: From 39b65ceba07228d188a9659253448b2554ae00c8 Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 31 May 2019 12:52:46 +0200 Subject: [PATCH 4/5] Add DS records to reverse zone --- domains/forms.py | 2 +- domains/models.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/domains/forms.py b/domains/forms.py index 744a920..4808387 100644 --- a/domains/forms.py +++ b/domains/forms.py @@ -210,7 +210,7 @@ class NameserverForm(MntFormMixin, WhoisObjectFormMixin, forms.ModelForm): return cleaned_data -class ReverseZoneForm(forms.ModelForm): +class ReverseZoneForm(DSRecordMixin, forms.ModelForm): prefix = forms.CharField(validators=[IP46CIDRValidator]) class Meta: diff --git a/domains/models.py b/domains/models.py index 16fd79a..b995466 100644 --- a/domains/models.py +++ b/domains/models.py @@ -13,6 +13,13 @@ import ipaddress # allow owners of a subnet to create reverse dns record? +class DSRecordModelMixin(models.Model): + class Meta: + abstract = True + + ds_records = models.TextField(blank=True, verbose_name='DS Records', + help_text='DS Records in the format of [id] [crypto-algo] [hash-algo] [hash]') + class Nameserver(MntdObject): handleSuffix = "NS" # dns name @@ -42,7 +49,7 @@ class Nameserver(MntdObject): return [] -class Domain(MntdObject): +class Domain(DSRecordModelMixin, MntdObject): handle = None handleSuffix = "DOM" name = models.CharField(max_length=67, unique=True, db_index=True) @@ -50,9 +57,6 @@ class Domain(MntdObject): nameservers = models.ManyToManyField(Nameserver, blank=True) admin_c = models.ManyToManyField(Contact) - ds_records = models.TextField(blank=True, verbose_name='DS Records', - help_text='DS Records in the format of [id] [crypto-algo] [hash-algo] [hash]') - def getPK(self): return self.name @@ -85,7 +89,7 @@ class Domain(MntdObject): return name.lower() -class ReverseZone(WhoisObject): +class ReverseZone(DSRecordModelMixin, WhoisObject): handle = None parentNet = models.ForeignKey(InetNum) From c800f853ac891f7de5a150e286fd8db2d4fe7dfb Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Fri, 31 May 2019 12:53:00 +0200 Subject: [PATCH 5/5] Compare records based on lowercase representation --- bin/dns-sync | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/dns-sync b/bin/dns-sync index e71c44e..f17045d 100755 --- a/bin/dns-sync +++ b/bin/dns-sync @@ -44,8 +44,8 @@ def mergeDomains(zoneData, pdnsData): found = False pdnsDom = list(filter(lambda _x: _x['name'] == domain and _x['type'] == rrType, rrData)) if len(pdnsDom) > 0: - rrSet = set(_x['content'] for _x in pdnsDom[0]['records']) - if rrSet == set(records): + rrSet = set(_x['content'].lower() for _x in pdnsDom[0]['records']) + if rrSet == set(record.lower() for record in records): found = True if not found: