Browse Source

Replace tabs with spaces

master^2
Sebastian Lohff 4 years ago
parent
commit
8384311517
  1. 212
      api/dnshelper.py
  2. 12
      api/urls.py
  3. 368
      api/views.py
  4. 301
      bin/dns-sync
  5. 194
      bin/import-data
  6. 8
      bin/markdown-to-html
  7. 28
      bin/roa-export
  8. 130
      bin/whoisd
  9. 6
      dncore/forms.py
  10. 2
      dncore/models.py
  11. 10
      dncore/urls.py
  12. 64
      dncore/views.py
  13. 104
      dnmgmt/settings.py
  14. 16
      dnmgmt/urls.py
  15. 378
      domains/forms.py
  16. 226
      domains/models.py
  17. 30
      domains/urls.py
  18. 186
      domains/views.py
  19. 68
      rrequests/forms.py
  20. 64
      rrequests/models.py
  21. 6
      rrequests/urls.py
  22. 142
      rrequests/views.py
  23. 52
      whoisdb/formfields.py
  24. 494
      whoisdb/forms.py
  25. 68
      whoisdb/generic.py
  26. 280
      whoisdb/helpers.py
  27. 402
      whoisdb/models.py
  28. 46
      whoisdb/templatetags/handletags.py
  29. 52
      whoisdb/urls.py
  30. 36
      whoisdb/validators.py
  31. 472
      whoisdb/views.py

212
api/dnshelper.py

@ -11,121 +11,121 @@ import dns.resolver @@ -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

12
api/urls.py

@ -7,13 +7,13 @@ from django.conf.urls import url @@ -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'),
]

368
api/views.py

@ -19,219 +19,219 @@ import ipaddress @@ -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)

301
bin/dns-sync

@ -25,179 +25,178 @@ __VERSION__ = '0.1' @@ -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()

194
bin/import-data

@ -24,107 +24,107 @@ from whoisdb.models import ASBlock, ASNumber, Contact, Maintainer, InetNum @@ -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()

8
bin/markdown-to-html

@ -12,11 +12,11 @@ import os @@ -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)])

28
bin/roa-export

@ -22,26 +22,26 @@ from whoisdb.models import ASNumber @@ -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()

130
bin/whoisd

@ -24,84 +24,84 @@ log = logging.getLogger("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()

6
dncore/forms.py

@ -7,6 +7,6 @@ from .models import User @@ -7,6 +7,6 @@ from .models import User
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ("username",)
class Meta:
model = User
fields = ("username",)

2
dncore/models.py

@ -7,4 +7,4 @@ from django.db import models @@ -7,4 +7,4 @@ from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
pass

10
dncore/urls.py

@ -8,10 +8,10 @@ from django.contrib.auth import views as auth_views @@ -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'),
]

64
dncore/views.py

@ -22,54 +22,54 @@ from .forms import CustomUserCreationForm @@ -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()
<