mirror of
				https://github.com/peeringdb/peeringdb.git
				synced 2024-05-11 05:55:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1647 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1647 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import os
 | |
| import json
 | |
| import datetime
 | |
| import re
 | |
| import uuid
 | |
| 
 | |
| from allauth.account.models import EmailAddress
 | |
| from django.http import (JsonResponse, HttpResponse, HttpResponseRedirect,
 | |
|                          HttpResponseNotFound, HttpResponseBadRequest,
 | |
|                          HttpResponseForbidden)
 | |
| from django.conf import settings as dj_settings
 | |
| from django.shortcuts import render
 | |
| from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
 | |
| from django.contrib.auth import authenticate, logout, login
 | |
| from django.contrib.auth.decorators import login_required
 | |
| from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie
 | |
| from django.views.decorators.http import require_http_methods
 | |
| from django.core.urlresolvers import resolve, Resolver404
 | |
| from django.template import loader
 | |
| from django.utils.crypto import constant_time_compare
 | |
| from django_namespace_perms.util import (
 | |
|     get_perms,
 | |
|     has_perms,
 | |
|     load_perms,
 | |
| )
 | |
| from django_namespace_perms.constants import (
 | |
|     PERM_CRUD,
 | |
|     PERM_CREATE,
 | |
|     PERM_DELETE,
 | |
|     PERM_WRITE,
 | |
| )
 | |
| import requests
 | |
| 
 | |
| from oauth2_provider.decorators import protected_resource
 | |
| from oauth2_provider.oauth2_backends import get_oauthlib_core
 | |
| 
 | |
| from peeringdb_server import settings
 | |
| from peeringdb_server.search import search
 | |
| from peeringdb_server.stats import stats as global_stats
 | |
| from peeringdb_server.org_admin_views import load_all_user_permissions
 | |
| from peeringdb_server.data_views import BOOL_CHOICE
 | |
| from peeringdb_server.models import (
 | |
|     UserOrgAffiliationRequest, User, UserPasswordReset, Organization, Network,
 | |
|     NetworkFacility, NetworkIXLan, InternetExchange, InternetExchangeFacility,
 | |
|     Facility, Sponsorship, Partnership, PARTNERSHIP_LEVELS, REFTAG_MAP, UTC)
 | |
| from peeringdb_server.forms import (UserCreationForm, PasswordResetForm,
 | |
|                                     PasswordChangeForm, AffiliateToOrgForm,
 | |
|                                     UsernameRetrieveForm, UserLocaleForm)
 | |
| from peeringdb_server.serializers import (
 | |
|     OrganizationSerializer, NetworkSerializer, InternetExchangeSerializer,
 | |
|     FacilitySerializer)
 | |
| from peeringdb_server.inet import RdapLookup, RdapException
 | |
| from peeringdb_server.mail import mail_username_retrieve
 | |
| from peeringdb_server.deskpro import ticket_queue_rdap_error
 | |
| 
 | |
| from ratelimit.decorators import ratelimit, is_ratelimited
 | |
| 
 | |
| RATELIMITS = dj_settings.RATELIMITS
 | |
| 
 | |
| from django.utils.translation import ugettext_lazy as _
 | |
| # lazy init for translations
 | |
| #_ = lambda s: s
 | |
| 
 | |
| BASE_ENV = {
 | |
|     'RECAPTCHA_PUBLIC_KEY': dj_settings.RECAPTCHA_PUBLIC_KEY,
 | |
|     'OAUTH_ENABLED': dj_settings.OAUTH_ENABLED,
 | |
|     'PEERINGDB_VERSION': settings.PEERINGDB_VERSION
 | |
| }
 | |
| 
 | |
| 
 | |
| def export_permissions(user, entity):
 | |
|     """
 | |
|     returns dict of permission bools for the specified user and entity
 | |
| 
 | |
|     to be used in template context
 | |
|     """
 | |
| 
 | |
|     if entity.status == "deleted":
 | |
|         return {}
 | |
| 
 | |
|     perms = {
 | |
|         "can_write": has_perms(user, entity, PERM_WRITE),
 | |
|         "can_create": has_perms(user, entity, PERM_CREATE),
 | |
|         "can_delete": has_perms(user, entity, PERM_DELETE)
 | |
|     }
 | |
| 
 | |
|     if entity.status == "pending":
 | |
|         perms["can_create"] = False
 | |
|         perms["can_delete"] = False
 | |
| 
 | |
|     if perms["can_write"] or perms["can_create"] or perms["can_delete"]:
 | |
|         perms["can_edit"] = True
 | |
| 
 | |
|     if hasattr(entity, "nsp_namespace_manage"):
 | |
|         perms["can_manage"] = has_perms(user, entity.nsp_namespace_manage,
 | |
|                                         PERM_CRUD)
 | |
|     else:
 | |
|         perms["can_manage"] = False
 | |
| 
 | |
|     return perms
 | |
| 
 | |
| 
 | |
| class DoNotRender(object):
 | |
|     """
 | |
|     Instance of this class is sent when a component attribute does not exist,
 | |
|     this can then be type checked in the templates to remove non existant attribute
 | |
|     rows while still allowing attributes with nonetype values to be rendered
 | |
|     """
 | |
| 
 | |
|     def all(self):
 | |
|         return []
 | |
| 
 | |
| 
 | |
| def make_env(**data):
 | |
|     env = {}
 | |
|     env.update(**BASE_ENV)
 | |
|     env.update(**{'global_stats': global_stats()})
 | |
|     env.update(**data)
 | |
|     return env
 | |
| 
 | |
| 
 | |
| def get_client_ip(request):
 | |
|     x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
 | |
|     if x_forwarded_for:
 | |
|         ip = x_forwarded_for.split(",")[0]
 | |
|     else:
 | |
|         ip = request.META.get("REMOTE_ADDR")
 | |
|     return ip
 | |
| 
 | |
| 
 | |
| def view_http_error_404(request):
 | |
|     template = loader.get_template('site/error_404.html')
 | |
|     return HttpResponseNotFound(template.render({}, request))
 | |
| 
 | |
| 
 | |
| def view_http_error_403(request):
 | |
|     template = loader.get_template('site/error_403.html')
 | |
|     return HttpResponseForbidden(template.render({}, request))
 | |
| 
 | |
| 
 | |
| def view_http_error_csrf(request, reason):
 | |
|     return JsonResponse({"non_field_errors": [reason]}, status=403)
 | |
| 
 | |
| 
 | |
| @login_required
 | |
| @ratelimit(key="ip", rate=RATELIMITS["view_request_ownership_GET"],
 | |
|            method="GET")
 | |
| @ratelimit(key="ip", rate=RATELIMITS["view_request_ownership_POST"],
 | |
|            method="POST")
 | |
| def view_request_ownership(request):
 | |
|     """
 | |
|     Renders the form that allows users to request ownership
 | |
|     to an unclaimed organization
 | |
|     """
 | |
| 
 | |
|     was_limited = getattr(request, "limited", False)
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
| 
 | |
|         # check if reuqest was blocked by rate limiting
 | |
|         if was_limited:
 | |
|             return view_index(request, errors=[
 | |
|                 _("Please wait a bit before requesting ownership again.")
 | |
|             ])
 | |
| 
 | |
|         org_id = request.GET.get("id")
 | |
|         try:
 | |
|             org = Organization.objects.get(id=org_id)
 | |
|         except Organization.DoesNotExist:
 | |
|             return view_index(request, errors=[_("Invalid organization")])
 | |
| 
 | |
|         if org.owned:
 | |
|             return view_index(request, errors=[
 | |
|                 _(u"Organization '%(org_name)s' is already under ownership") %
 | |
|                 {
 | |
|                     'org_name': org.name
 | |
|                 }
 | |
|             ])
 | |
| 
 | |
|         template = loader.get_template("site/request-ownership.html")
 | |
|         return HttpResponse(template.render(make_env(org=org), request))
 | |
| 
 | |
|     elif request.method == "POST":
 | |
| 
 | |
|         org_id = request.POST.get("id")
 | |
| 
 | |
|         # check if reuqest was blocked by rate limiting
 | |
|         if was_limited:
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [
 | |
|                     _("Please wait a bit before requesting ownership again.")
 | |
|                 ]
 | |
|             }, status=400)
 | |
| 
 | |
|         try:
 | |
|             org = Organization.objects.get(id=org_id)
 | |
|         except Organization.DoesNotExist:
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [_("Organization does not exist")]
 | |
|             }, status=400)
 | |
| 
 | |
|         if org.owned:
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [
 | |
|                     _("Organization '%(org_name)s' is already under ownership")
 | |
|                     % {
 | |
|                         'org_name': org.name
 | |
|                     }
 | |
|                 ]
 | |
|             }, status=400)
 | |
| 
 | |
|         if UserOrgAffiliationRequest.objects.filter(user=request.user,
 | |
|                                                     org=org).exists():
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [
 | |
|                     _("You already have an ownership request pending for this organization"
 | |
|                       )
 | |
|                 ]
 | |
|             }, status=400)
 | |
| 
 | |
|         uoar = UserOrgAffiliationRequest.objects.create(
 | |
|             user=request.user, org=org, status="pending")
 | |
|         return JsonResponse({"status": "ok", "ownership_status": uoar.status})
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| @ratelimit(key="ip", method="POST",
 | |
|            rate=RATELIMITS["view_affiliate_to_org_POST"])
 | |
| def view_affiliate_to_org(request):
 | |
|     """
 | |
|     Allows the user to request affiliation with an organization through
 | |
|     an ASN they provide
 | |
|     """
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return view_login(request)
 | |
| 
 | |
|     if request.method == "POST":
 | |
| 
 | |
|         # check if request was blocked by rate limiting
 | |
|         was_limited = getattr(request, "limited", False)
 | |
|         if was_limited:
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [
 | |
|                     _("Please wait a bit before requesting affiliation again.")
 | |
|                 ]
 | |
|             }, status=400)
 | |
| 
 | |
|         form = AffiliateToOrgForm(request.POST)
 | |
|         if not form.is_valid():
 | |
|             return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|         if not form.cleaned_data.get("org") and not form.cleaned_data.get(
 | |
|                 "asn") and not form.cleaned_data.get("org_name"):
 | |
|             return JsonResponse({
 | |
|                 "asn": _("Either ASN or Organization required"),
 | |
|                 "org": _("Either ASN or Organization required")
 | |
|             }, status=400)
 | |
| 
 | |
|         asn = form.cleaned_data.get("asn")
 | |
| 
 | |
|         # remove all deleted uoars for user
 | |
|         UserOrgAffiliationRequest.objects.filter(user=request.user,
 | |
|                                                  status="denied").delete()
 | |
| 
 | |
|         try:
 | |
| 
 | |
|             uoar, created = UserOrgAffiliationRequest.objects.get_or_create(
 | |
|                 user=request.user, asn=form.cleaned_data.get("asn"),
 | |
|                 org_id=form.cleaned_data.get("org") or None,
 | |
|                 org_name=form.cleaned_data.get("org_name") or None,
 | |
|                 status="pending")
 | |
| 
 | |
|         except RdapException as exc:
 | |
|             ticket_queue_rdap_error(request.user, asn, exc)
 | |
|             return JsonResponse({
 | |
|                 "asn": _("RDAP Lookup Error: {}").format(exc)
 | |
|             }, status=400)
 | |
| 
 | |
|         except MultipleObjectsReturned:
 | |
|             pass
 | |
| 
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
|     return view_verify(request)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| @ratelimit(key='ip', rate=RATELIMITS["resend_confirmation_mail"])
 | |
| def resend_confirmation_mail(request):
 | |
|     was_limited = getattr(request, 'limited', False)
 | |
|     if was_limited:
 | |
|         return view_index(request, errors=[
 | |
|             _("Please wait a bit before trying to resend the confirmation email again"
 | |
|               )
 | |
|         ])
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return view_login(request)
 | |
| 
 | |
|     request.user.send_email_confirmation(request=request)
 | |
|     return view_index(request,
 | |
|                       errors=[_("We have resent your confirmation email")])
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| def view_profile(request):
 | |
|     return view_verify(request)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| def view_set_user_locale(request):
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return view_login(request)
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         return view_verify(request)
 | |
|     elif request.method == "POST":
 | |
| 
 | |
|         form = UserLocaleForm(request.POST)
 | |
|         if not form.is_valid():
 | |
|             return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|         loc = form.cleaned_data.get("locale")
 | |
|         request.user.set_locale(loc)
 | |
| 
 | |
|         from django.utils import translation
 | |
|         translation.activate(loc)
 | |
|         request.session[translation.LANGUAGE_SESSION_KEY] = loc
 | |
| 
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @protected_resource(scopes=['profile'])
 | |
| def view_profile_v1(request):
 | |
|     #    if not request.user.is_authenticated():
 | |
|     #        return view_login(request)
 | |
|     oauth = get_oauthlib_core()
 | |
|     scope_email, _request = oauth.verify_request(request, scopes=["email"])
 | |
|     scope_networks, _request = oauth.verify_request(request,
 | |
|                                                     scopes=["networks"])
 | |
| 
 | |
|     json_params = {}
 | |
|     if "pretty" in request.GET:
 | |
|         json_params['indent'] = 2
 | |
| 
 | |
|     user = request.user
 | |
|     data = dict(
 | |
|         id=request.user.id,
 | |
|         given_name=request.user.first_name,
 | |
|         family_name=request.user.last_name,
 | |
|         name=request.user.full_name,
 | |
|         verified_user=user.is_verified,
 | |
|     )
 | |
| 
 | |
|     # only add email fields if email scope is present
 | |
|     if scope_email:
 | |
|         data.update(
 | |
|             dict(
 | |
|                 email=request.user.email,
 | |
|                 verified_email=user.email_confirmed,
 | |
|             ))
 | |
| 
 | |
|     # only add ddnetworks if networks scope is present
 | |
|     if scope_networks:
 | |
|         networks = []
 | |
|         load_perms(user)
 | |
|         for net in user.networks:
 | |
|             crud = get_perms(user._nsp_perms_struct,
 | |
|                              net.nsp_namespace.split(".")).value
 | |
|             networks.append(
 | |
|                 dict(
 | |
|                     id=net.id,
 | |
|                     name=net.name,
 | |
|                     asn=net.asn,
 | |
|                     perms=crud,
 | |
|                 ))
 | |
| 
 | |
|         data['networks'] = networks
 | |
| 
 | |
|     return JsonResponse(data, json_dumps_params=json_params)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| @ratelimit(key='ip', rate=RATELIMITS["view_verify_POST"], method="POST")
 | |
| def view_verify(request):
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return view_login(request)
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         template = loader.get_template("site/verify.html")
 | |
|         env = BASE_ENV.copy()
 | |
|         env.update({
 | |
|             'affiliation_request':
 | |
|                 request.user.affiliation_requests.order_by("-created").first(),
 | |
|             'affiliations': request.user.organizations,
 | |
|             'global_stats': global_stats(),
 | |
|         })
 | |
|         return HttpResponse(template.render(env, request))
 | |
|     elif request.method == "POST":
 | |
| 
 | |
|         # change email address
 | |
| 
 | |
|         password = request.POST.get("password")
 | |
| 
 | |
|         was_limited = getattr(request, "limited", False)
 | |
| 
 | |
|         if was_limited:
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [
 | |
|                     _("Please wait a bit before requesting another email change"
 | |
|                       )
 | |
|                 ]
 | |
|             }, status=400)
 | |
| 
 | |
|         if not request.user.has_oauth:
 | |
|             if not authenticate(username=request.user.username,
 | |
|                                 password=password):
 | |
|                 return JsonResponse({"status": "auth"}, status=401)
 | |
| 
 | |
|         if EmailAddress.objects.filter(user=request.user).exists():
 | |
|             EmailAddress.objects.filter(user=request.user).delete()
 | |
| 
 | |
|         request.user.email = request.POST.get("email")
 | |
| 
 | |
|         if User.objects.filter(email=request.user.email).exclude(
 | |
|                 id=request.user.id).exists():
 | |
|             return JsonResponse({
 | |
|                 "email": _("E-mail already exists in our system")
 | |
|             }, status=400)
 | |
|         request.user.clean()
 | |
|         request.user.save()
 | |
| 
 | |
|         request.user.send_email_confirmation(request=request)
 | |
| 
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| def view_password_change(request):
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return view_login(request)
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         return view_verify(request)
 | |
|     elif request.method == "POST":
 | |
| 
 | |
|         password_c = request.POST.get("password_c")
 | |
| 
 | |
|         if not request.user.has_oauth:
 | |
|             if not authenticate(username=request.user.username,
 | |
|                                 password=password_c):
 | |
|                 return JsonResponse({
 | |
|                     "status": "auth",
 | |
|                     "password_c": _("Wrong password")
 | |
|                 }, status=400)
 | |
|         else:
 | |
|             return JsonResponse({"status": "auth"}, status=401)
 | |
| 
 | |
|         form = PasswordChangeForm(request.POST)
 | |
|         if not form.is_valid():
 | |
|             return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|         request.user.set_password(form.cleaned_data.get("password"))
 | |
|         request.user.save()
 | |
| 
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| @require_http_methods(["GET"])
 | |
| def view_username_retrieve(request):
 | |
|     """
 | |
|     username retrieval view
 | |
|     """
 | |
|     env = BASE_ENV.copy()
 | |
|     env.update({
 | |
|         'global_stats': global_stats(),
 | |
|     })
 | |
|     return render(request, "site/username-retrieve.html", env)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| @require_http_methods(["POST"])
 | |
| @ratelimit(key='ip', rate=RATELIMITS["view_username_retrieve_initiate"])
 | |
| def view_username_retrieve_initiate(request):
 | |
|     """
 | |
|     username retrieval initiate view
 | |
|     """
 | |
| 
 | |
|     was_limited = getattr(request, "limited", False)
 | |
|     if was_limited:
 | |
|         return JsonResponse({
 | |
|             "non_field_errors": [
 | |
|                 _("Please wait a bit before requesting your usernames again.")
 | |
|             ]
 | |
|         }, status=400)
 | |
| 
 | |
|     # clean form and get email address
 | |
|     form = UsernameRetrieveForm(request.POST)
 | |
|     if not form.is_valid():
 | |
|         return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|     email = form.cleaned_data.get("email")
 | |
| 
 | |
|     # generate secret and store in user's django sessions
 | |
|     secret = str(uuid.uuid4())
 | |
|     request.session["username_retrieve_secret"] = secret
 | |
|     request.session["username_retrieve_email"] = email
 | |
| 
 | |
|     # send email
 | |
|     if User.objects.filter(email=email).exists():
 | |
|         mail_username_retrieve(email, secret)
 | |
| 
 | |
|     return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| @require_http_methods(["GET"])
 | |
| def view_username_retrieve_complete(request):
 | |
|     """
 | |
|     username retrieval completion view
 | |
| 
 | |
|     show the list of usernames associated to an email if
 | |
|     the correct secret is provided
 | |
|     """
 | |
| 
 | |
|     secret = request.GET.get("secret")
 | |
|     secret_expected = request.session.get("username_retrieve_secret")
 | |
|     email = request.session.get("username_retrieve_email")
 | |
|     env = BASE_ENV.copy()
 | |
|     env.update({
 | |
|         "secret": secret,
 | |
|         "secret_expected": secret_expected,
 | |
|         "users": User.objects.filter(email=email),
 | |
|         "email": email
 | |
|     })
 | |
| 
 | |
|     if secret_expected and constant_time_compare(secret, secret_expected):
 | |
|         # invalidate the username retrieve session
 | |
|         del request.session["username_retrieve_email"]
 | |
|         del request.session["username_retrieve_secret"]
 | |
|         request.session.modified = True
 | |
| 
 | |
|     return render(request, "site/username-retrieve-complete.html", env)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| def view_password_reset(request):
 | |
|     """
 | |
|     password reset initiation view
 | |
|     """
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         env = BASE_ENV.copy()
 | |
|         env.update({
 | |
|             'global_stats': global_stats(),
 | |
|         })
 | |
| 
 | |
|         env["token"] = token = request.GET.get("token")
 | |
|         env["target"] = target = request.GET.get("target")
 | |
| 
 | |
|         if token and target:
 | |
|             pr = UserPasswordReset.objects.filter(user_id=target).first()
 | |
|             env["pr"] = pr
 | |
| 
 | |
|             if pr and pr.match(token) and pr.is_valid():
 | |
|                 env["username"] = pr.user.username
 | |
|                 env["token_valid"] = True
 | |
| 
 | |
|         template = loader.get_template("site/password-reset.html")
 | |
| 
 | |
|         return HttpResponse(template.render(env, request))
 | |
| 
 | |
|     elif request.method == "POST":
 | |
| 
 | |
|         token = request.POST.get("token")
 | |
|         target = request.POST.get("target")
 | |
|         if token and target:
 | |
|             form = PasswordChangeForm(request.POST)
 | |
|             if not form.is_valid():
 | |
|                 return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|             user = User.objects.filter(id=target).first()
 | |
| 
 | |
|             err_invalid_token_msg = _("Invalid Security Token")
 | |
|             err_expired_msg = ('{} <a href="/reset-password">{}</a>').format(
 | |
|                 _("Password Reset Process has expired, please"),
 | |
|                 _("initiate again"))
 | |
| 
 | |
|             if user:
 | |
|                 try:
 | |
|                     if not user.password_reset.match(token):
 | |
|                         return JsonResponse({
 | |
|                             "non_field_errors": [err_invalid_token_msg]
 | |
|                         }, status=400)
 | |
| 
 | |
|                     if not user.password_reset.is_valid():
 | |
|                         return JsonResponse({
 | |
|                             "non_field_errors": [err_expired_msg]
 | |
|                         }, status=400)
 | |
| 
 | |
|                 except UserPasswordReset.DoesNotExist:
 | |
|                     return JsonResponse({
 | |
|                         "non_field_errors": [err_expired_msg]
 | |
|                     }, status=400)
 | |
| 
 | |
|                 user.password_reset_complete(token,
 | |
|                                              form.cleaned_data.get("password"))
 | |
| 
 | |
|             else:
 | |
|                 return JsonResponse({
 | |
|                     "non_field_errors": [err_expired_msg]
 | |
|                 }, status=400)
 | |
| 
 | |
|         else:
 | |
|             form = PasswordResetForm(request.POST)
 | |
| 
 | |
|             if not form.is_valid():
 | |
|                 return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|             user = User.objects.filter(
 | |
|                 email=form.cleaned_data["email"]).first()
 | |
|             if user:
 | |
|                 user.password_reset_initiate()
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| def view_registration(request):
 | |
|     """
 | |
|     user registration page view
 | |
|     """
 | |
|     if request.user.is_authenticated():
 | |
|         return view_index(request, errors=[
 | |
|             _('Please log out of your current session before trying to register. Notice, multiple accounts are no longer needed.'
 | |
|               )
 | |
|         ])
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         template = loader.get_template("site/register.html")
 | |
|         env = BASE_ENV.copy()
 | |
|         env.update({
 | |
|             'global_stats': global_stats(),
 | |
|         })
 | |
|         return HttpResponse(template.render(env, request))
 | |
| 
 | |
|     elif request.method == "POST":
 | |
|         form = UserCreationForm(request.POST)
 | |
| 
 | |
|         if not form.is_valid():
 | |
|             return JsonResponse(form.errors, status=400)
 | |
| 
 | |
|         cpt = request.POST.get("recaptcha", "")
 | |
|         cpt_params = {
 | |
|             "secret": dj_settings.RECAPTCHA_SECRET_KEY,
 | |
|             "response": cpt,
 | |
|             "remoteip": get_client_ip(request)
 | |
|         }
 | |
|         cpt_response = requests.post(dj_settings.RECAPTCHA_VERIFY_URL,
 | |
|                                      params=cpt_params).json()
 | |
|         if not cpt_response.get("success"):
 | |
|             return JsonResponse({
 | |
|                 "non_field_errors": [_("reCAPTCHA invalid")]
 | |
|             }, status=400)
 | |
| 
 | |
|         email = form.cleaned_data["email"]
 | |
|         if EmailAddress.objects.filter(email=email).count() > 0:
 | |
|             return JsonResponse({
 | |
|                 "email": _("This email address has already been used")
 | |
|             }, status=400)
 | |
| 
 | |
|         # require min password length
 | |
|         # FIXME: impl password strength validation
 | |
|         if len(form.cleaned_data["password1"]) < 10:
 | |
|             return JsonResponse({
 | |
|                 "password1": _("Needs to be at least 10 characters long")
 | |
|             }, status=400)
 | |
| 
 | |
|         # create the user
 | |
|         user = form.save()
 | |
| 
 | |
|         user.set_unverified()
 | |
| 
 | |
|         # log the user in
 | |
|         login(request,
 | |
|               authenticate(username=request.POST["username"],
 | |
|                            password=request.POST["password1"]))
 | |
| 
 | |
|         user.send_email_confirmation(signup=True, request=request)
 | |
| 
 | |
|         return JsonResponse({"status": "ok"})
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_login(request, errors=None):
 | |
|     """
 | |
|     login page view
 | |
|     """
 | |
|     if not errors:
 | |
|         errors = []
 | |
| 
 | |
|     if request.user.is_authenticated():
 | |
|         return view_index(request, errors=[_('Already logged in')])
 | |
| 
 | |
|     template = loader.get_template('site/login.html')
 | |
| 
 | |
|     env = BASE_ENV.copy()
 | |
|     env.update({'errors': errors})
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_index(request, errors=None):
 | |
|     """
 | |
|     landing page view
 | |
|     """
 | |
|     if not errors:
 | |
|         errors = []
 | |
| 
 | |
|     template = loader.get_template('site/index.html')
 | |
| 
 | |
|     recent = {
 | |
|         "net": Network.handleref.filter(status="ok").order_by("-updated")[:5],
 | |
|         "fac": Facility.handleref.filter(status="ok").order_by("-updated")[:5],
 | |
|         "ix": InternetExchange.handleref.filter(status="ok")
 | |
|               .order_by("-updated")[:5]
 | |
|     }
 | |
| 
 | |
|     env = BASE_ENV.copy()
 | |
|     env.update({
 | |
|         'errors': errors,
 | |
|         'global_stats': global_stats(),
 | |
|         'recent': recent
 | |
|     })
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def view_component(request, component, data, title, perms=None, instance=None,
 | |
|                    **kwargs):
 | |
|     """
 | |
|     Generic component view
 | |
|     """
 | |
|     if not perms:
 | |
|         perms = {}
 | |
| 
 | |
|     template = loader.get_template('site/view.html')
 | |
| 
 | |
|     env = BASE_ENV.copy()
 | |
|     env.update({
 | |
|         'data': data,
 | |
|         'permissions': perms,
 | |
|         'title': title,
 | |
|         'component': component,
 | |
|         'instance': instance,
 | |
|         'ref_tag': instance._handleref.tag,
 | |
|         'global_stats': global_stats(),
 | |
|         'asset_template_name': 'site/view_%s_assets.html' % component,
 | |
|         'tools_template_name': 'site/view_%s_tools.html' % component,
 | |
|         'side_template_name': 'site/view_%s_side.html' % component,
 | |
|         'bottom_template_name': 'site/view_%s_bottom.html' % component
 | |
|     })
 | |
|     env.update(**kwargs)
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_organization(request, id):
 | |
|     """
 | |
|     View organization data for org specified by id
 | |
|     """
 | |
| 
 | |
|     try:
 | |
|         org = OrganizationSerializer.prefetch_related(
 | |
|             Organization.objects, request, depth=2).get(
 | |
|                 id=id, status__in=["ok", "pending"])
 | |
|     except ObjectDoesNotExist:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
|     data = OrganizationSerializer(org, context={"user": request.user}).data
 | |
| 
 | |
|     if not data:
 | |
|         return view_http_error_403(request)
 | |
| 
 | |
|     perms = export_permissions(request.user, org)
 | |
| 
 | |
|     tags = ["fac", "net", "ix"]
 | |
|     for tag in tags:
 | |
|         model = REFTAG_MAP.get(tag)
 | |
|         perms["can_create_%s" % tag] = has_perms(request.user,
 | |
|                                                  model.nsp_namespace_from_id(
 | |
|                                                      org.id, "create"),
 | |
|                                                  PERM_CREATE)
 | |
|         perms["can_delete_%s" % tag] = has_perms(request.user,
 | |
|                                                  model.nsp_namespace_from_id(
 | |
|                                                      org.id, "_").strip("_"),
 | |
|                                                  PERM_DELETE)
 | |
| 
 | |
|     # if the organization being viewed is the one used
 | |
|     # to store suggested entities, we dont want to show the editorial
 | |
|     # tools
 | |
|     if org.id == dj_settings.SUGGEST_ENTITY_ORG:
 | |
|         perms["can_create"] = False
 | |
|         perms["can_manage"] = False
 | |
|         for tag in tags:
 | |
|             perms["can_create_%s" % tag] = False
 | |
|             perms["can_delete_%s" % tag] = False
 | |
| 
 | |
|     # if user has writing perms to entity, we want to load sub entities
 | |
|     # that have status pending so we dont use the ones kicked back
 | |
|     # by the serializer
 | |
|     if perms.get("can_delete_ix") or perms.get("can_create_ix"):
 | |
|         exchanges = org.ix_set.filter(status__in=["ok", "pending"])
 | |
|     else:
 | |
|         exchanges = data["ix_set"]
 | |
| 
 | |
|     if perms.get("can_delete_fac") or perms.get("can_create_fac"):
 | |
|         facilities = org.fac_set.filter(status__in=["ok", "pending"])
 | |
|     else:
 | |
|         facilities = data["fac_set"]
 | |
| 
 | |
|     if perms.get("can_delete_net") or perms.get("can_create_net"):
 | |
|         networks = org.net_set.filter(status__in=["ok", "pending"])
 | |
|     else:
 | |
|         networks = data["net_set"]
 | |
| 
 | |
|     dismiss = DoNotRender()
 | |
| 
 | |
|     data = {
 | |
|         "title": data.get("name", dismiss),
 | |
|         "exchanges": exchanges,
 | |
|         "networks": networks,
 | |
|         "facilities": facilities,
 | |
|         "fields": [{
 | |
|             "name": "website",
 | |
|             "type": "url",
 | |
|             "notify_incomplete": True,
 | |
|             "value": data.get("website", dismiss),
 | |
|             "label": _("Website")
 | |
|         }, {
 | |
|             "name": "address1",
 | |
|             "label": _("Address 1"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": data.get("address1", dismiss)
 | |
|         }, {
 | |
|             "name": "address2",
 | |
|             "label": _("Address 2"),
 | |
|             "value": data.get("address2", dismiss)
 | |
|         }, {
 | |
|             "name": "location",
 | |
|             "label": _("Location"),
 | |
|             "type": "location",
 | |
|             "notify_incomplete": True,
 | |
|             "value": data
 | |
|         }, {
 | |
|             "name": "country",
 | |
|             "type": "list",
 | |
|             "data": "countries_b",
 | |
|             "label": _("Country Code"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": data.get("country", dismiss)
 | |
|         }, {
 | |
|             "name": "notes",
 | |
|             "label": _("Notes"),
 | |
|             "help_text": _("Markdown enabled"),
 | |
|             "type": "fmt-text",
 | |
|             "value": data.get("notes", dismiss)
 | |
|         }]
 | |
|     }
 | |
| 
 | |
|     users = {}
 | |
|     if perms.get("can_manage"):
 | |
|         users.update(
 | |
|             dict([(user.id, user)
 | |
|                   for user in org.admin_usergroup.user_set.all()]))
 | |
|         users.update(
 | |
|             dict([(user.id, user) for user in org.usergroup.user_set.all()]))
 | |
|         users = sorted(users.values(), key=lambda x: x.full_name)
 | |
| 
 | |
|     # if user has rights to create sub entties or manage users, allow them
 | |
|     # to view the tools
 | |
|     if perms.get("can_manage") or perms.get("can_create"):
 | |
|         perms["can_use_tools"] = True
 | |
| 
 | |
|     active_tab = None
 | |
|     tab_init = {}
 | |
|     for tag in tags:
 | |
|         tab_init[tag] = "inactive"
 | |
|         if perms.get("can_create_%s" % tag):
 | |
|             perms["can_use_tools"] = True
 | |
|             if not active_tab:
 | |
|                 tab_init[tag] = "active"
 | |
|                 active_tab = tag
 | |
|         if perms.get("can_delete_%s" % tag):
 | |
|             perms["can_edit"] = True
 | |
| 
 | |
|     if perms.get("can_manage") and org.pending_affiliations.count() > 0:
 | |
|         tab_init = {"users": "active"}
 | |
| 
 | |
|     return view_component(
 | |
|         request, "organization", data, "Organization", tab_init=tab_init,
 | |
|         users=users, user_perms=load_all_user_permissions(org), instance=org,
 | |
|         perms=perms)
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_facility(request, id):
 | |
|     """
 | |
|     View facility data for facility specified by id
 | |
|     """
 | |
| 
 | |
|     try:
 | |
|         facility = Facility.objects.get(id=id, status__in=["ok", "pending"])
 | |
|     except ObjectDoesNotExist:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
|     data = FacilitySerializer(facility, context={"user": request.user}).data
 | |
| 
 | |
|     if not data:
 | |
|         return view_http_error_403(request)
 | |
| 
 | |
|     perms = export_permissions(request.user, facility)
 | |
| 
 | |
|     org = OrganizationSerializer(facility.org, context={
 | |
|         "user": request.user
 | |
|     }).data
 | |
| 
 | |
|     exchanges = InternetExchangeFacility.handleref.undeleted().filter(
 | |
|         facility=facility).select_related("ix").order_by("ix__name").all()
 | |
|     peers = NetworkFacility.handleref.undeleted().filter(
 | |
|         facility=facility).select_related("network").order_by("network__name")
 | |
| 
 | |
|     dismiss = DoNotRender()
 | |
| 
 | |
|     data = {
 | |
|         "title": data.get("name", dismiss),
 | |
|         "exchanges": exchanges,
 | |
|         "peers": peers,
 | |
|         "fields": [{
 | |
|             "name": "org",
 | |
|             "label": _("Organization"),
 | |
|             "value": org.get("name", dismiss),
 | |
|             "type": "entity_link",
 | |
|             "link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
 | |
|         }, {
 | |
|             "name": "website",
 | |
|             "type": "url",
 | |
|             "value": data.get("website", dismiss),
 | |
|             "label": _("Website")
 | |
|         }, {
 | |
|             "name": "address1",
 | |
|             "label": _("Address 1"),
 | |
|             "value": data.get("address1", dismiss)
 | |
|         }, {
 | |
|             "name": "address2",
 | |
|             "label": _("Address 2"),
 | |
|             "value": data.get("address2", dismiss)
 | |
|         }, {
 | |
|             "name": "location",
 | |
|             "label": _("Location"),
 | |
|             "type": "location",
 | |
|             "value": data
 | |
|         }, {
 | |
|             "name": "country",
 | |
|             "type": "list",
 | |
|             "data": "countries_b",
 | |
|             "label": _("Country Code"),
 | |
|             "value": data.get("country", dismiss)
 | |
|         }, {
 | |
|             "name": "geocode",
 | |
|             "label": _("Geocode"),
 | |
|             "type": "geocode",
 | |
|             "value": data
 | |
|         }, {
 | |
|             "name": "clli",
 | |
|             "label": _("CLLI Code"),
 | |
|             "value": data.get("clli", dismiss)
 | |
|         }, {
 | |
|             "name": "npanxx",
 | |
|             "label": _("NPA-NXX"),
 | |
|             "value": data.get("npanxx", dismiss)
 | |
|         }, {
 | |
|             "name": "notes",
 | |
|             "label": _("Notes"),
 | |
|             "help_text": _("Markdown enabled"),
 | |
|             "type": "fmt-text",
 | |
|             "value": data.get("notes", dismiss)
 | |
|         }]
 | |
|     }
 | |
| 
 | |
|     return view_component(request, "facility", data, "Facility", perms=perms,
 | |
|                           instance=facility)
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_exchange(request, id):
 | |
|     """
 | |
|     View exchange data for exchange specified by id
 | |
|     """
 | |
| 
 | |
|     try:
 | |
|         exchange = InternetExchange.objects.get(id=id,
 | |
|                                                 status__in=["ok", "pending"])
 | |
|     except ObjectDoesNotExist:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
|     data = InternetExchangeSerializer(exchange, context={
 | |
|         "user": request.user
 | |
|     }).data
 | |
| 
 | |
|     # find out if user can write to object
 | |
|     perms = export_permissions(request.user, exchange)
 | |
| 
 | |
|     if not data:
 | |
|         return view_http_error_403(request)
 | |
|     networks = NetworkIXLan.handleref.undeleted().select_related(
 | |
|         'network',
 | |
|         'ixlan').order_by('network__name').filter(ixlan__ix=exchange)
 | |
|     dismiss = DoNotRender()
 | |
| 
 | |
|     facilities = InternetExchangeFacility.handleref.undeleted().select_related(
 | |
|         'ix', 'facility').filter(ix=exchange).order_by("facility__name")
 | |
| 
 | |
|     org = data.get("org")
 | |
| 
 | |
|     data = {
 | |
|         "id": exchange.id,
 | |
|         "title": data.get("name", dismiss),
 | |
|         "facilities": facilities,
 | |
|         "networks": networks,
 | |
|         "ixlans": exchange.ixlan_set_active_or_pending,
 | |
|         "fields": [{
 | |
|             "name": "org",
 | |
|             "label": _("Organization"),
 | |
|             "value": org.get("name", dismiss),
 | |
|             "type": "entity_link",
 | |
|             "link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
 | |
|         }, {
 | |
|             "name": "name_long",
 | |
|             "label": _("Long Name"),
 | |
|             "value": data.get("name_long", dismiss)
 | |
|         }, {
 | |
|             "name": "city",
 | |
|             "label": _("City"),
 | |
|             "value": data.get("city", dismiss)
 | |
|         }, {
 | |
|             "name": "country",
 | |
|             "type": "list",
 | |
|             "data": "countries_b",
 | |
|             "label": _("Country"),
 | |
|             "value": data.get("country", dismiss)
 | |
|         }, {
 | |
|             "name": "region_continent",
 | |
|             "type": "list",
 | |
|             "data": "enum/regions",
 | |
|             "label": _("Continental Region"),
 | |
|             "value": data.get("region_continent", dismiss)
 | |
|         }, {
 | |
|             "name": "media",
 | |
|             "type": "list",
 | |
|             "data": "enum/media",
 | |
|             "label": _("Media Type"),
 | |
|             "value": data.get("media", dismiss)
 | |
|         }, {
 | |
|             "type": "flags",
 | |
|             "label": _("Protocols Supported"),
 | |
|             "value": [{
 | |
|                 "name": "proto_unicast",
 | |
|                 "label": _("Unicast IPv4"),
 | |
|                 "value": int(data.get("proto_unicast", False))
 | |
|             }, {
 | |
|                 "name": "proto_multicast",
 | |
|                 "label": _("Multicast"),
 | |
|                 "value": int(data.get("proto_multicast", False))
 | |
|             }, {
 | |
|                 "name": "proto_ipv6",
 | |
|                 "label": _("IPv6"),
 | |
|                 "value": int(data.get("proto_ipv6", False))
 | |
|             }]
 | |
|         }, {
 | |
|             "name": "notes",
 | |
|             "label": _("Notes"),
 | |
|             "help_text": _("Markdown enabled"),
 | |
|             "type": "fmt-text",
 | |
|             "value": data.get("notes", dismiss)
 | |
|         }, {
 | |
|             "type": "sub",
 | |
|             "label": _("Contact Information")
 | |
|         }, {
 | |
|             "type": "url",
 | |
|             "name": "website",
 | |
|             "label": _("Company Website"),
 | |
|             "value": data.get("website", dismiss)
 | |
|         }, {
 | |
|             "type": "url",
 | |
|             "name": "url_stats",
 | |
|             "label": _("Traffic Stats Website"),
 | |
|             "value": data.get("url_stats", dismiss)
 | |
|         }, {
 | |
|             "type": "email",
 | |
|             "name": "tech_email",
 | |
|             "label": _("Technical Email"),
 | |
|             "value": data.get("tech_email", dismiss)
 | |
|         }, {
 | |
|             "type": "string",
 | |
|             "name": "tech_phone",
 | |
|             "label": _("Technical Phone"),
 | |
|             "value": data.get("tech_phone", dismiss)
 | |
|         }, {
 | |
|             "type": "email",
 | |
|             "name": "policy_email",
 | |
|             "label": _("Policy Email"),
 | |
|             "value": data.get("policy_email", dismiss)
 | |
|         }, {
 | |
|             "type": "string",
 | |
|             "name": "policy_phone",
 | |
|             "label": _("Policy Phone"),
 | |
|             "value": data.get("policy_phone", dismiss)
 | |
|         }]
 | |
|     }
 | |
| 
 | |
|     ixlan_num = data["ixlans"].count()
 | |
| 
 | |
|     if ixlan_num < 2 and not perms.get("can_edit"):
 | |
|         # if there is less than one LAN connected to this ix
 | |
|         # we want to render a simplified view to read-only
 | |
|         # viewers
 | |
| 
 | |
|         data["lan_simple_view"] = True
 | |
| 
 | |
|         if ixlan_num == 1:
 | |
| 
 | |
|             ixlan = data["ixlans"].first()
 | |
| 
 | |
|             data["fields"].extend([{
 | |
|                 "type": "sub",
 | |
|                 "label": _("LAN")
 | |
|             }, {
 | |
|                 "type": "number",
 | |
|                 "name": "mtu",
 | |
|                 "label": _("MTU"),
 | |
|                 "value": ixlan.mtu or ""
 | |
|             }, {
 | |
|                 "type": "bool",
 | |
|                 "name": "dot1q_support",
 | |
|                 "label": _("DOT1Q"),
 | |
|                 "value": ixlan.dot1q_support
 | |
|             }])
 | |
| 
 | |
|             data["fields"].extend([{
 | |
|                 "type": "string",
 | |
|                 "name": "prefix_%d" % prefix.id,
 | |
|                 "label": _(prefix.protocol),
 | |
|                 "value": prefix.prefix
 | |
|             } for prefix in ixlan.ixpfx_set_active])
 | |
| 
 | |
|     return view_component(request, "exchange", data, "Exchange", perms=perms,
 | |
|                           instance=exchange)
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_network_by_query(request):
 | |
|     if "asn" in request.GET:
 | |
|         try:
 | |
|             return view_network_by_asn(request, request.GET.get("asn"))
 | |
|         except ValueError:
 | |
|             return view_http_error_404(request)
 | |
|     else:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_network_by_asn(request, asn):
 | |
|     try:
 | |
|         network = Network.objects.get(asn=int(asn))
 | |
|         # FIXME: should be able to just pass existing network object here to avoid
 | |
|         # having to query again
 | |
|         return view_network(request, network.id)
 | |
|     except ObjectDoesNotExist:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
| 
 | |
| @ensure_csrf_cookie
 | |
| def view_network(request, id):
 | |
|     """
 | |
|     View network data for network specified by id
 | |
|     """
 | |
| 
 | |
|     try:
 | |
|         network = NetworkSerializer.prefetch_related(
 | |
|             Network.objects, request, depth=2).get(
 | |
|                 id=id, status__in=["ok", "pending"])
 | |
|     except ObjectDoesNotExist:
 | |
|         return view_http_error_404(request)
 | |
| 
 | |
|     network_d = NetworkSerializer(network, context={"user": request.user}).data
 | |
| 
 | |
|     if not network_d:
 | |
|         return view_http_error_403(request)
 | |
| 
 | |
|     perms = export_permissions(request.user, network)
 | |
| 
 | |
|     facilities = NetworkFacility.handleref.undeleted().select_related(
 | |
|         "facility").filter(network=network).order_by("facility__name")
 | |
| 
 | |
|     exchanges = NetworkIXLan.handleref.undeleted().select_related(
 | |
|         "ixlan", "ixlan__ix",
 | |
|         "network").filter(network=network).order_by("ixlan__ix__name")
 | |
| 
 | |
|     # This will be passed as default value for keys that dont exist - causing
 | |
|     # them not to be rendered in the template - also it is fairly
 | |
|     # safe to assume that no existing keys have been dropped because permission
 | |
|     # requirements to view them were not met.
 | |
|     dismiss = DoNotRender()
 | |
| 
 | |
|     org = network_d.get("org")
 | |
| 
 | |
|     data = {
 | |
|         "title": network_d.get("name", dismiss),
 | |
|         "facilities": facilities,
 | |
|         "exchanges": exchanges,
 | |
|         "fields": [{
 | |
|             "name": "org",
 | |
|             "label": _("Organization"),
 | |
|             "value": org.get("name", dismiss),
 | |
|             "type": "entity_link",
 | |
|             "link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
 | |
|         }, {
 | |
|             "name": "aka",
 | |
|             "label": _("Also Known As"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("aka", dismiss)
 | |
|         }, {
 | |
|             "name": "website",
 | |
|             "label": _("Company Website"),
 | |
|             "type": "url",
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("website", dismiss)
 | |
|         }, {
 | |
|             "name": "asn",
 | |
|             "label": _("Primary ASN"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("asn", dismiss)
 | |
|         }, {
 | |
|             "name": "irr_as_set",
 | |
|             "label": _("IRR Record"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("irr_as_set", dismiss)
 | |
|         }, {
 | |
|             "name": "route_server",
 | |
|             "type": "url",
 | |
|             "label": _("Route Server URL"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("route_server", dismiss)
 | |
|         }, {
 | |
|             "name": "looking_glass",
 | |
|             "type": "url",
 | |
|             "label": _("Looking Glass URL"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("looking_glass", dismiss)
 | |
|         }, {
 | |
|             "name": "info_type",
 | |
|             "type": "list",
 | |
|             "data": "enum/net_types",
 | |
|             "blank": _("Not Disclosed"),
 | |
|             "label": _("Network Type"),
 | |
|             "notify_incomplete": True,
 | |
|             "value": network_d.get("info_type", dismiss)
 | |
|         }, {
 | |
|             "name": "info_prefixes4",
 | |
|             "label": _("IPv4 Prefixes"),
 | |
|             "type": "number",
 | |
|             "notify_incomplete": True,
 | |
|             "value": int(network_d.get("info_prefixes4") or 0)
 | |
|         }, {
 | |
|             "name": "info_prefixes6",
 | |
|             "label": _("IPv6 Prefixes"),
 | |
|             "type": "number",
 | |
|             "notify_incomplete": True,
 | |
|             "value": int(network_d.get("info_prefixes6") or 0)
 | |
|         }, {
 | |
|             "name": "info_traffic",
 | |
|             "type": "list",
 | |
|             "data": "enum/traffic",
 | |
|             "blank": _("Not Disclosed"),
 | |
|             "label": _("Traffic Levels"),
 | |
|             "value": network_d.get("info_traffic", dismiss)
 | |
|         }, {
 | |
|             "name": "info_ratio",
 | |
|             "type": "list",
 | |
|             "data": "enum/ratios",
 | |
|             "label": _("Traffic Ratios"),
 | |
|             "blank": _("Not Disclosed"),
 | |
|             "value": network_d.get("info_ratio", dismiss)
 | |
|         }, {
 | |
|             "name": "info_scope",
 | |
|             "type": "list",
 | |
|             "data": "enum/scopes",
 | |
|             "blank": _("Not Disclosed"),
 | |
|             "label": _("Geographic Scope"),
 | |
|             "value": network_d.get("info_scope", dismiss)
 | |
|         }, {
 | |
|             "type": "flags",
 | |
|             "label": _("Protocols Supported"),
 | |
|             "value": [{
 | |
|                 "name": "info_unicast",
 | |
|                 "label": _("Unicast IPv4"),
 | |
|                 "value": network_d.get("info_unicast", False)
 | |
|             }, {
 | |
|                 "name": "info_multicast",
 | |
|                 "label": _("Multicast"),
 | |
|                 "value": network_d.get("info_multicast", False)
 | |
|             }, {
 | |
|                 "name": "info_ipv6",
 | |
|                 "label": _("IPv6"),
 | |
|                 "value": network_d.get("info_ipv6", False)
 | |
|             }]
 | |
|         }, {
 | |
|             "readonly": True,
 | |
|             "name": "updated",
 | |
|             "label": _("Last Updated"),
 | |
|             "value": network_d.get("updated", dismiss)
 | |
|         }, {
 | |
|             "name": "notes",
 | |
|             "label": _("Notes"),
 | |
|             "help_text": _("Markdown enabled"),
 | |
|             "type": "fmt-text",
 | |
|             "value": network_d.get("notes", dismiss)
 | |
|         }, {
 | |
|             "type": "sub",
 | |
|             "admin": True,
 | |
|             "label": _("PeeringDB Configuration")
 | |
|         }, {
 | |
|             "type": "flags",
 | |
|             "admin": True,
 | |
|             "label": _("Allow IXP Update"),
 | |
|             "help_text": _(
 | |
|                 "If enabled, an ixp may manage this network's entry in their peering list"
 | |
|             ),
 | |
|             "value": [{
 | |
|                 "name": "allow_ixp_update",
 | |
|                 "label": "",
 | |
|                 "value": network.allow_ixp_update
 | |
|             }]
 | |
|         }, {
 | |
|             "type": "sub",
 | |
|             "label": _("Peering Policy Information")
 | |
|         }, {
 | |
|             "name": "policy_url",
 | |
|             "label": _("Peering Policy"),
 | |
|             "value": network_d.get("policy_url", dismiss),
 | |
|             "notify_incomplete": True,
 | |
|             "type": "url"
 | |
|         }, {
 | |
|             "name": "policy_general",
 | |
|             "type": "list",
 | |
|             "data": "enum/policy_general",
 | |
|             "label": _("General Policy"),
 | |
|             "value": network_d.get("policy_general", dismiss)
 | |
|         }, {
 | |
|             "name": "policy_locations",
 | |
|             "type": "list",
 | |
|             "data": "enum/policy_locations",
 | |
|             "label": _("Multiple Locations"),
 | |
|             "value": network_d.get("policy_locations", dismiss)
 | |
|         }, {
 | |
|             "name": "policy_ratio",
 | |
|             "type": "list",
 | |
|             "data": "enum/bool_choice_str",
 | |
|             "label": _("Ratio Requirement"),
 | |
|             "value": network_d.get("policy_ratio", dismiss),
 | |
|             "value_label": dict(BOOL_CHOICE).get(
 | |
|                 network_d.get("policy_ratio"))
 | |
|         }, {
 | |
|             "name": "policy_contracts",
 | |
|             "type": "list",
 | |
|             "data": "enum/policy_contracts",
 | |
|             "label": _("Contract Requirement"),
 | |
|             "value": network_d.get("policy_contracts", dismiss)
 | |
|         }]
 | |
|     }
 | |
| 
 | |
|     # Add POC data to dataset
 | |
|     data["poc_set"] = network_d.get("poc_set")
 | |
| 
 | |
|     if not request.user.is_authenticated() or not request.user.is_verified:
 | |
|         cnt = network.poc_set.filter(status="ok", visible="Users").count()
 | |
|         data["poc_hidden"] = (cnt > 0)
 | |
|     else:
 | |
|         data["poc_hidden"] = False
 | |
| 
 | |
|     return view_component(request, "network", data, "Network", perms=perms,
 | |
|                           instance=network)
 | |
| 
 | |
| 
 | |
| def view_suggest(request, reftag):
 | |
|     if reftag not in ["net", "ix", "fac"]:
 | |
|         return HttpResponseRedirect("/")
 | |
| 
 | |
|     template = loader.get_template("site/view_suggest_{}.html".format(reftag))
 | |
|     env = make_env()
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def view_simple_content(request, content_name):
 | |
|     """
 | |
|     Renders the content in templates/{{ content_name }} inside
 | |
|     the peeringdb layout
 | |
|     """
 | |
| 
 | |
|     template = loader.get_template("site/simple_content.html")
 | |
| 
 | |
|     env = make_env(content_name=content_name)
 | |
| 
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def view_aup(request):
 | |
|     """
 | |
|     Render page containing acceptable use policy
 | |
|     """
 | |
| 
 | |
|     return view_simple_content(request, "site/aup.html")
 | |
| 
 | |
| 
 | |
| def view_sponsorships(request):
 | |
|     """
 | |
|     View current sponsorships
 | |
|     """
 | |
| 
 | |
|     template = loader.get_template("site/sponsorships.html")
 | |
|     now = datetime.datetime.now().replace(tzinfo=UTC())
 | |
| 
 | |
|     qset = Sponsorship.objects.filter(start_date__lte=now, end_date__gte=now,
 | |
|                                       logo__isnull=False)
 | |
| 
 | |
|     sponsorships = {
 | |
|         "diamond": qset.filter(level=4),
 | |
|         "platinum": qset.filter(level=3),
 | |
|         "gold": qset.filter(level=2),
 | |
|         "silver": qset.filter(level=1)
 | |
|     }
 | |
| 
 | |
|     env = make_env(sponsorships=sponsorships)
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def view_partnerships(request):
 | |
|     """
 | |
|     View current partners
 | |
|     """
 | |
| 
 | |
|     template = loader.get_template("site/partnerships.html")
 | |
|     qset = Partnership.objects.filter(logo__isnull=False)
 | |
| 
 | |
|     partnerships = {}
 | |
|     for row in qset:
 | |
|         if row.level not in partnerships:
 | |
|             partnerships[row.level] = []
 | |
|         partnerships[row.level].append(row)
 | |
| 
 | |
|     env = make_env(
 | |
|         partnership_levels=dict(PARTNERSHIP_LEVELS), partnerships=partnerships)
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def view_advanced_search(request):
 | |
|     """
 | |
|     View for advanced search
 | |
|     """
 | |
| 
 | |
|     template = loader.get_template("site/advanced-search.html")
 | |
|     env = make_env(row_limit=getattr(dj_settings, "API_DEPTH_ROW_LIMIT", 250))
 | |
| 
 | |
|     reftag = request.GET.get("reftag")
 | |
| 
 | |
|     if reftag == "net":
 | |
|         try:
 | |
|             env["ix_name"] = InternetExchange.objects.get(
 | |
|                 id=request.GET.get("ix")).name
 | |
|         except (ObjectDoesNotExist, ValueError):
 | |
|             env["ix_name"] = ""
 | |
| 
 | |
|         try:
 | |
|             env["not_ix_name"] = InternetExchange.objects.get(
 | |
|                 id=request.GET.get("not_ix")).name
 | |
|         except (ObjectDoesNotExist, ValueError):
 | |
|             env["not_ix_name"] = ""
 | |
| 
 | |
|         try:
 | |
|             env["fac_name"] = Facility.objects.get(
 | |
|                 id=request.GET.get("fac")).name
 | |
|         except (ObjectDoesNotExist, ValueError):
 | |
|             env["fac_name"] = ""
 | |
| 
 | |
|         try:
 | |
|             env["not_fac_name"] = Facility.objects.get(
 | |
|                 id=request.GET.get("not_fac")).name
 | |
|         except (ObjectDoesNotExist, ValueError):
 | |
|             env["not_fac_name"] = ""
 | |
| 
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def request_api_search(request):
 | |
|     q = request.GET.get('q')
 | |
| 
 | |
|     if not q:
 | |
|         return HttpResponseBadRequest()
 | |
| 
 | |
|     result = search(q)
 | |
| 
 | |
|     return HttpResponse(json.dumps(result), content_type='application/json')
 | |
| 
 | |
| 
 | |
| def request_search(request):
 | |
|     """
 | |
|     XHR search request goes here
 | |
|     """
 | |
|     q = request.GET.get('q')
 | |
| 
 | |
|     if not q:
 | |
|         return HttpResponseRedirect("/")
 | |
| 
 | |
|     # if the user queried for an asn directly via ASXXX or ASNXXX
 | |
|     # redirect to the result
 | |
|     m = re.match(r"(asn|as)(\d+)", q.lower())
 | |
|     if m:
 | |
|         net = Network.objects.filter(asn=m.group(2), status="ok")
 | |
|         if net.exists() and net.count() == 1:
 | |
|             return HttpResponseRedirect('/net/{}'.format(net.first().id))
 | |
| 
 | |
|     result = search(q)
 | |
| 
 | |
|     template = loader.get_template('site/search_result.html')
 | |
|     env = make_env(
 | |
|         **{
 | |
|             'search_ixp': result.get(InternetExchange._handleref.tag),
 | |
|             'search_net': result.get(Network._handleref.tag),
 | |
|             'search_fac': result.get(Facility._handleref.tag),
 | |
|             'count_ixp': len(result.get(InternetExchange._handleref.tag, [])),
 | |
|             'count_net': len(result.get(Network._handleref.tag, [])),
 | |
|             'count_fac': len(result.get(Facility._handleref.tag, []))
 | |
|         })
 | |
|     return HttpResponse(template.render(env, request))
 | |
| 
 | |
| 
 | |
| def request_logout(request):
 | |
|     logout(request)
 | |
|     return view_index(request)
 | |
| 
 | |
| 
 | |
| @csrf_protect
 | |
| @ensure_csrf_cookie
 | |
| @ratelimit(key="ip", rate=RATELIMITS["request_login_POST"], method="POST")
 | |
| def request_login(request):
 | |
| 
 | |
|     if request.user.is_authenticated():
 | |
|         return view_index(request)
 | |
| 
 | |
|     if request.method in ["GET", "HEAD"]:
 | |
|         return view_login(request)
 | |
| 
 | |
|     was_limited = getattr(request, "limited", False)
 | |
|     if was_limited:
 | |
|         return view_login(request, errors=[
 | |
|             _("Please wait a bit before trying to login again.")
 | |
|         ])
 | |
| 
 | |
|     username = request.POST['username']
 | |
|     password = request.POST['password']
 | |
|     redir = request.POST.get("next") or "/"
 | |
|     if redir == "/logout":
 | |
|         redir = "/"
 | |
| 
 | |
|     try:
 | |
|         resolve(redir)
 | |
|     except Resolver404:
 | |
|         redir = "/"
 | |
| 
 | |
|     user = authenticate(username=username, password=password)
 | |
|     if user is not None:
 | |
|         if user.is_active:
 | |
|             login(request, user)
 | |
| 
 | |
|             from django.utils import translation
 | |
|             user_language = user.get_locale()
 | |
|             translation.activate(user_language)
 | |
|             request.session[translation.LANGUAGE_SESSION_KEY] = user_language
 | |
| 
 | |
|             return HttpResponseRedirect(redir)
 | |
|         return view_login(request, errors=[_("Account disabled.")])
 | |
|     return view_login(request, errors=[_("Invalid username/password.")])
 | |
| 
 | |
| 
 | |
| @require_http_methods(["POST"])
 | |
| @ratelimit(key="ip", rate=RATELIMITS["request_translation"], method="POST")
 | |
| def request_translation(request, data_type):
 | |
| 
 | |
|     if not request.user.is_authenticated():
 | |
|         return JsonResponse({
 | |
|             "status": 'error',
 | |
|             "error": "Please login to use translation service"
 | |
|         })
 | |
| 
 | |
|     user_language = request.user.get_locale()
 | |
|     if not user_language:
 | |
|         user_language = 'en'
 | |
| 
 | |
|     note = request.POST.get("note")
 | |
|     target = user_language
 | |
| 
 | |
|     if note and target:
 | |
| 
 | |
|         translationURL = 'https://translation.googleapis.com/language/translate/v2'
 | |
|         call_params = {
 | |
|             'key': dj_settings.GOOGLE_GEOLOC_API_KEY,
 | |
|             'q': note,
 | |
|             'target': target
 | |
|         }
 | |
|         reply = requests.post(translationURL, params=call_params).json()
 | |
| 
 | |
|         if not "data" in reply:
 | |
|             return JsonResponse({"status": request.POST, "error": reply})
 | |
| 
 | |
|         return JsonResponse({
 | |
|             "status": request.POST,
 | |
|             "translation": reply["data"]["translations"][0]
 | |
|         })
 | |
| 
 | |
|     return JsonResponse({
 | |
|         "status": 'error',
 | |
|         "error": "No text or no language specified"
 | |
|     })
 |