mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-25 03:58:39 +02:00
Merge pull request #2843 from cisagov/es/2589-rdap-api
2589: RDAP API endpoint [rh]
This commit is contained in:
commit
ab5cd2c9ae
4 changed files with 87 additions and 27 deletions
66
src/api/tests/test_rdap.py
Normal file
66
src/api/tests/test_rdap.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
"""Test the domain rdap lookup API."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.test import RequestFactory
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from ..views import rdap
|
||||||
|
|
||||||
|
API_BASE_PATH = "/api/v1/rdap/?domain="
|
||||||
|
|
||||||
|
|
||||||
|
class RdapViewTest(TestCase):
|
||||||
|
"""Test that the RDAP view function works as expected"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = get_user_model().objects.create(username="username")
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
|
def test_rdap_get_no_tld(self):
|
||||||
|
"""RDAP API successfully fetches RDAP for domain without a TLD"""
|
||||||
|
request = self.factory.get(API_BASE_PATH + "whitehouse")
|
||||||
|
request.user = self.user
|
||||||
|
response = rdap(request, domain="whitehouse")
|
||||||
|
# contains the right text
|
||||||
|
self.assertContains(response, "rdap")
|
||||||
|
# can be parsed into JSON with appropriate keys
|
||||||
|
response_object = json.loads(response.content)
|
||||||
|
self.assertIn("rdapConformance", response_object)
|
||||||
|
|
||||||
|
def test_rdap_invalid_domain(self):
|
||||||
|
"""RDAP API accepts invalid domain queries and returns JSON response
|
||||||
|
with appropriate error codes"""
|
||||||
|
request = self.factory.get(API_BASE_PATH + "whitehouse.com")
|
||||||
|
request.user = self.user
|
||||||
|
response = rdap(request, domain="whitehouse.com")
|
||||||
|
|
||||||
|
self.assertContains(response, "errorCode")
|
||||||
|
response_object = json.loads(response.content)
|
||||||
|
self.assertIn("errorCode", response_object)
|
||||||
|
|
||||||
|
|
||||||
|
class RdapAPITest(TestCase):
|
||||||
|
"""Test that the API can be called as expected."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
username = "test_user"
|
||||||
|
first_name = "First"
|
||||||
|
last_name = "Last"
|
||||||
|
email = "info@example.com"
|
||||||
|
title = "title"
|
||||||
|
phone = "8080102431"
|
||||||
|
self.user = get_user_model().objects.create(
|
||||||
|
username=username, title=title, first_name=first_name, last_name=last_name, email=email, phone=phone
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rdap_get(self):
|
||||||
|
"""Can call RDAP API"""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get(API_BASE_PATH + "whitehouse.gov")
|
||||||
|
self.assertContains(response, "rdap")
|
||||||
|
response_object = json.loads(response.content)
|
||||||
|
self.assertIn("rdapConformance", response_object)
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from registrar.templatetags.url_helpers import public_site_url
|
from registrar.templatetags.url_helpers import public_site_url
|
||||||
|
@ -18,7 +18,7 @@ from cachetools.func import ttl_cache
|
||||||
from registrar.utility.s3_bucket import S3ClientError, S3ClientHelper
|
from registrar.utility.s3_bucket import S3ClientError, S3ClientHelper
|
||||||
|
|
||||||
|
|
||||||
DOMAIN_FILE_URL = "https://raw.githubusercontent.com/cisagov/dotgov-data/main/current-full.csv"
|
RDAP_URL = "https://rdap.cloudflareregistry.com/rdap/domain/{domain}"
|
||||||
|
|
||||||
|
|
||||||
DOMAIN_API_MESSAGES = {
|
DOMAIN_API_MESSAGES = {
|
||||||
|
@ -41,30 +41,6 @@ DOMAIN_API_MESSAGES = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# this file doesn't change that often, nor is it that big, so cache the result
|
|
||||||
# in memory for ten minutes
|
|
||||||
@ttl_cache(ttl=600)
|
|
||||||
def _domains():
|
|
||||||
"""Return a list of the current .gov domains.
|
|
||||||
|
|
||||||
Fetch a file from DOMAIN_FILE_URL, parse the CSV for the domain,
|
|
||||||
lowercase everything and return the list.
|
|
||||||
"""
|
|
||||||
DraftDomain = apps.get_model("registrar.DraftDomain")
|
|
||||||
# 5 second timeout
|
|
||||||
file_contents = requests.get(DOMAIN_FILE_URL, timeout=5).text
|
|
||||||
domains = set()
|
|
||||||
# skip the first line
|
|
||||||
for line in file_contents.splitlines()[1:]:
|
|
||||||
# get the domain before the first comma
|
|
||||||
domain = line.split(",", 1)[0]
|
|
||||||
# sanity-check the string we got from the file here
|
|
||||||
if DraftDomain.string_could_be_domain(domain):
|
|
||||||
# lowercase everything when we put it in domains
|
|
||||||
domains.add(domain.lower())
|
|
||||||
return domains
|
|
||||||
|
|
||||||
|
|
||||||
def check_domain_available(domain):
|
def check_domain_available(domain):
|
||||||
"""Return true if the given domain is available.
|
"""Return true if the given domain is available.
|
||||||
|
|
||||||
|
@ -99,6 +75,22 @@ def available(request, domain=""):
|
||||||
return json_response
|
return json_response
|
||||||
|
|
||||||
|
|
||||||
|
@require_http_methods(["GET"])
|
||||||
|
@login_not_required
|
||||||
|
# Since we cache domain RDAP data, cache time may need to be re-evaluated this if we encounter any memory issues
|
||||||
|
@ttl_cache(ttl=600)
|
||||||
|
def rdap(request, domain=""):
|
||||||
|
"""Returns JSON dictionary of a domain's RDAP data from Cloudflare API"""
|
||||||
|
domain = request.GET.get("domain", "")
|
||||||
|
|
||||||
|
# If inputted domain doesn't have a TLD, append .gov to it
|
||||||
|
if "." not in domain:
|
||||||
|
domain = f"{domain}.gov"
|
||||||
|
|
||||||
|
rdap_data = requests.get(RDAP_URL.format(domain=domain), timeout=5).json()
|
||||||
|
return JsonResponse(rdap_data)
|
||||||
|
|
||||||
|
|
||||||
@require_http_methods(["GET"])
|
@require_http_methods(["GET"])
|
||||||
@login_not_required
|
@login_not_required
|
||||||
def get_current_full(request, file_name="current-full.csv"):
|
def get_current_full(request, file_name="current-full.csv"):
|
||||||
|
|
|
@ -32,7 +32,7 @@ from registrar.views.utility.api_views import (
|
||||||
)
|
)
|
||||||
from registrar.views.domains_json import get_domains_json
|
from registrar.views.domains_json import get_domains_json
|
||||||
from registrar.views.utility import always_404
|
from registrar.views.utility import always_404
|
||||||
from api.views import available, get_current_federal, get_current_full
|
from api.views import available, rdap, get_current_federal, get_current_full
|
||||||
|
|
||||||
|
|
||||||
DOMAIN_REQUEST_NAMESPACE = views.DomainRequestWizard.URL_NAMESPACE
|
DOMAIN_REQUEST_NAMESPACE = views.DomainRequestWizard.URL_NAMESPACE
|
||||||
|
@ -194,6 +194,7 @@ urlpatterns = [
|
||||||
path("openid/", include("djangooidc.urls")),
|
path("openid/", include("djangooidc.urls")),
|
||||||
path("request/", include((domain_request_urls, DOMAIN_REQUEST_NAMESPACE))),
|
path("request/", include((domain_request_urls, DOMAIN_REQUEST_NAMESPACE))),
|
||||||
path("api/v1/available/", available, name="available"),
|
path("api/v1/available/", available, name="available"),
|
||||||
|
path("api/v1/rdap/", rdap, name="rdap"),
|
||||||
path("api/v1/get-report/current-federal", get_current_federal, name="get-current-federal"),
|
path("api/v1/get-report/current-federal", get_current_federal, name="get-current-federal"),
|
||||||
path("api/v1/get-report/current-full", get_current_full, name="get-current-full"),
|
path("api/v1/get-report/current-full", get_current_full, name="get-current-full"),
|
||||||
path(
|
path(
|
||||||
|
|
|
@ -116,6 +116,7 @@ class TestURLAuth(TestCase):
|
||||||
"/api/v1/available/",
|
"/api/v1/available/",
|
||||||
"/api/v1/get-report/current-federal",
|
"/api/v1/get-report/current-federal",
|
||||||
"/api/v1/get-report/current-full",
|
"/api/v1/get-report/current-full",
|
||||||
|
"/api/v1/rdap/",
|
||||||
"/health",
|
"/health",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue