Skip to content

Commit

Permalink
Merge pull request #199 from hcrudolph/development
Browse files Browse the repository at this point in the history
Adds APIv2 endpoints, updates dependencies
  • Loading branch information
hcrudolph authored Nov 27, 2023
2 parents 2befc80 + 3c16f36 commit 9599699
Show file tree
Hide file tree
Showing 6 changed files with 1,047 additions and 76 deletions.
24 changes: 22 additions & 2 deletions api/urls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.urls import path, re_path
import api.views as views
import api.views as views

urlpatterns = [
path('', views.api_root),
Expand All @@ -8,6 +8,26 @@
path('cs/software/<software>/', views.cs_by_software),
path('cs/tls/<tlsv>/', views.cs_by_tlsversion),
path('rfc/', views.rfc_all),
re_path(r'^cs/(?P<iana_name>[a-zA-Z0-9_]+)/$', views.cs_single),
path('cs/<iana_name>/', views.cs_single),
re_path(r'^rfc/(?P<rfc_number>[0-9]+)/$', views.rfc_single),

path('v2/', views.api_root_v2),
path('v2/cs/', views.cs_all_v2),
path('v2/cs/<algo_type>/<search_term>/', views.search_cs_by_algorithm_v2),
path('v2/cs/security/<sec_level>/', views.cs_by_security_v2),
path('v2/cs/software/<software>/', views.cs_by_software_v2),
path('v2/cs/tls/<tls_version>/', views.cs_by_tlsversion_v2),
path('v2/cs/<iana_name>/', views.cs_single_v2),

path('v2/algo/', views.algo_all_v2),
path('v2/algo/type/<algo_type>/', views.algo_by_type_v2),
path('v2/algo/sev/<severity>/', views.algo_by_severity_v2),

path('v2/vuln/', views.vuln_all_v2),
path('v2/vuln/<vuln_name>/', views.vuln_by_name_v2),
path('v2/vuln/sev/<severity>/', views.vuln_by_severity_v2),
path('v2/vuln/cs/<iana_name>/', views.vuln_by_csname_v2),

path('v2/rfc/', views.rfc_all_v2),
re_path(r'^v2/rfc/(?P<rfc_number>[0-9]+)/$', views.rfc_single_v2),
]
218 changes: 179 additions & 39 deletions api/views.py
Original file line number Diff line number Diff line change
@@ -1,63 +1,99 @@
from django.shortcuts import get_object_or_404, render, redirect
from django.http import JsonResponse, HttpResponse, Http404
from directory.models import CipherSuite, Rfc
from django.shortcuts import get_object_or_404, get_list_or_404
from django.http import JsonResponse, HttpResponse, Http404, HttpResponseBadRequest
from django.forms.models import model_to_dict
from django.conf import settings
from directory.models import *
from os.path import join

# Helper variables

secmap = dict(insecure=3, weak=2, secure=1, recommended=0)
vulnmap = dict(low=0, medium=1, high=2)

# Helper functions

def reformat_cs(cs):
# replace int security rating by string
if cs['security'] == 0:
cs['security'] = "recommended"
cs.update(security="recommended")
elif cs['security'] == 1:
cs['security'] = "secure"
cs.update(security="secure")
elif cs['security'] == 2:
cs['security'] = "weak"
cs.update(security="weak")
elif cs['security'] == 3:
cs['security'] = "insecure"

cs.update(security="insecure")
return {cs.pop('name'):cs}

def reformat_cs_v2(cs):
# replace int security rating by string
if cs['security'] == 0:
cs.update(security="recommended")
elif cs['security'] == 1:
cs.update(security="secure")
elif cs['security'] == 2:
cs.update(security="weak")
elif cs['security'] == 3:
cs.update(security="insecure")
cs.update(iana_name=cs.pop('name'))
cs.pop('protocol_version')
return cs

def reformat_rfc(rfc):
return {rfc.pop('number'):rfc}

def reformat_vuln_v2(vuln):
if vuln['severity'] == 0:
vuln.update(severity="low")
elif vuln['severity'] == 1:
vuln.update(severity="medium")
else:
vuln.update(severity="high")
return vuln

# Root

def api_root(request):
api_definition = open(join(settings.BASE_DIR, 'static/openapi.json'), 'rb')
response = HttpResponse(content=api_definition)
response['Content-Type'] = 'application/json'
return response

def api_root_v2(request):
api_definition = open(join(settings.BASE_DIR, 'static/openapi_v2.json'), 'rb')
response = HttpResponse(content=api_definition)
response['Content-Type'] = 'application/json'
return response

# Cyphersuites

def cs_all(request):
cs = [reformat_cs(x.to_dict()) for x in CipherSuite.objects.all()]
return JsonResponse({"ciphersuites":cs}, safe=False)

def cs_all_v2(request):
cs = [reformat_cs_v2(x.to_dict()) for x in CipherSuite.objects.all()]
return JsonResponse(cs, safe=False)

def cs_single(request, iana_name):
cs = get_object_or_404(CipherSuite, pk=iana_name)
return JsonResponse(reformat_cs(cs.to_dict()), safe=False)

def cs_single_v2(request, iana_name):
cs = get_object_or_404(CipherSuite, pk=iana_name)
return JsonResponse(reformat_cs_v2(cs.to_dict()), safe=False)

def cs_by_security(request, sec_level):
if sec_level == 'insecure':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(security=3)]
elif sec_level == 'weak':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(security=2)]
elif sec_level == 'secure':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(security=1)]
elif sec_level == 'recommended':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(security=0)]
else:
raise Http404(f"Security level '{sec_level}' does not exist.")

cs = [reformat_cs(cs.to_dict()) for cs in
get_list_or_404(CipherSuite, security=secmap[sec_level])]
return JsonResponse({"ciphersuites":cs}, safe=False)

def cs_by_security_v2(request, sec_level):
if not sec_level in secmap:
return HttpResponseBadRequest('Illegal security rating.', status=400)

cs = [reformat_cs_v2(cs.to_dict()) for cs in
get_list_or_404(CipherSuite, security=secmap[sec_level])]
return JsonResponse({"ciphersuites":cs}, safe=False)

def cs_by_software(request, software):
if software == 'openssl':
Expand All @@ -71,31 +107,135 @@ def cs_by_software(request, software):

return JsonResponse({"ciphersuites":cs}, safe=False)


def cs_by_tlsversion(request, tlsv):
if tlsv == '10':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(tls_version__short="10")]
elif tlsv == '11':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(tls_version__short="11")]
elif tlsv == '12':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(tls_version__short="12")]
elif tlsv == '13':
cs = [reformat_cs(cs.to_dict()) for cs in
CipherSuite.objects.filter(tls_version__short="13")]
def cs_by_software_v2(request, software):
if software == 'openssl':
cs = [reformat_cs_v2(cs.to_dict()) for cs in
CipherSuite.objects.exclude(openssl_name="")]
elif software == 'gnutls':
cs = [reformat_cs_v2(cs.to_dict()) for cs in
CipherSuite.objects.exclude(gnutls_name="")]
else:
raise Http404(f"TLS version '{tlsv}' does not exist.")
return HttpResponseBadRequest('Illegal software library.', status=400)

return JsonResponse(cs, safe=False)

def cs_by_tlsversion(request, tlsv):
cs = [reformat_cs(cs.to_dict()) for cs in
get_list_or_404(CipherSuite, tls_version__short=tlsv)]
return JsonResponse({"ciphersuites":cs}, safe=False)

def cs_by_tlsversion_v2(request, tls_version):
if not tls_version in [10, 11, 12, 13]:
return HttpResponseBadRequest('Illegal TLS version.', status=400)

cs = [reformat_cs_v2(cs.to_dict()) for cs in
get_list_or_404(CipherSuite, tls_version__short=tls_version)]
return JsonResponse(cs, safe=False)

def search_cs_by_algorithm_v2(request, algo_type, search_term):
if algo_type == "keyx":
cs = [reformat_cs_v2(x.to_dict()) for x in
get_list_or_404(CipherSuite,
kex_algorithm__short_name__icontains=search_term)]
elif algo_type == "auth":
cs = [reformat_cs_v2(x.to_dict()) for x in
get_list_or_404(CipherSuite,
auth_algorithm__short_name__icontains=search_term)]
elif algo_type == "encr":
cs = [reformat_cs_v2(x.to_dict()) for x in
get_list_or_404(CipherSuite,
enc_algorithm__short_name__icontains=search_term)]
elif algo_type == "hash":
cs = [reformat_cs_v2(x.to_dict()) for x in
get_list_or_404(CipherSuite,
hash_algorithm__short_name__icontains=search_term)]
else:
return HttpResponseBadRequest('Illegal algorithm type.', status=400)
return JsonResponse(cs, safe=False)

# RFCs

def rfc_all(request):
rfc = [reformat_rfc(x.to_dict()) for x in Rfc.objects.all()]
return JsonResponse({"rfcs":rfc}, safe=False)

def rfc_all_v2(request):
rfc = [x.to_dict() for x in Rfc.objects.all()]
return JsonResponse(rfc, safe=False)

def rfc_single(request, rfc_number):
rfc = get_object_or_404(Rfc, pk=rfc_number)
return JsonResponse(reformat_rfc(rfc.to_dict()), safe=False)
return JsonResponse(reformat_rfc(rfc.to_dict()), safe=False)

def rfc_single_v2(request, rfc_number):
rfc = get_object_or_404(Rfc, pk=rfc_number)
return JsonResponse(rfc.to_dict(), safe=False)

# Algorithms

def algo_all_v2(request):
keyx = [dict(x.to_dict(), algo_type="keyx") for
x in KexAlgorithm.objects.all()]
auth = [dict(x.to_dict(), algo_type="auth") for
x in AuthAlgorithm.objects.all()]
encr = [dict(x.to_dict(), algo_type="encr") for
x in EncAlgorithm.objects.all()]
hash = [dict(x.to_dict(), algo_type="hash") for
x in HashAlgorithm.objects.all()]
algo = keyx + auth + encr + hash
return JsonResponse(algo, safe=False)

def algo_by_type_v2(request, algo_type):
if algo_type == "keyx":
algo = [x.to_dict() for x in KexAlgorithm.objects.all()]
elif algo_type == "auth":
algo = [x.to_dict() for x in AuthAlgorithm.objects.all()]
elif algo_type == "encr":
algo = [x.to_dict() for x in EncAlgorithm.objects.all()]
elif algo_type == "hash":
algo = [x.to_dict() for x in HashAlgorithm.objects.all()]
else:
return HttpResponseBadRequest('Illegal algorithm type.', status=400)
return JsonResponse(algo, safe=False)

def algo_by_severity_v2(request, severity):
if not severity in vulnmap:
return HttpResponseBadRequest('Illegal severity rating.', status=400)

keyx = [dict(x.to_dict(), type="keyx") for x in
get_list_or_404(KexAlgorithm, vulnerabilities__severity=vulnmap[severity])]
auth = [dict(x.to_dict(), type="auth") for x in
get_list_or_404(AuthAlgorithm, vulnerabilities__severity=vulnmap[severity])]
encr = [dict(x.to_dict(), type="encr") for x in
get_list_or_404(EncAlgorithm, vulnerabilities__severity=vulnmap[severity])]
hash = [dict(x.to_dict(), type="hash") for x in
get_list_or_404(HashAlgorithm, vulnerabilities__severity=vulnmap[severity])]
algo = keyx + auth + encr + hash
return JsonResponse(algo, safe=False)

# Vulnerabilities

def vuln_all_v2(request):
vuln = [reformat_vuln_v2(x.to_dict()) for x in Vulnerability.objects.all()]
return JsonResponse(vuln, safe=False)

def vuln_by_name_v2(request, vuln_name):
vuln = get_object_or_404(Vulnerability, pk=vuln_name)
return JsonResponse(reformat_vuln_v2(vuln.to_dict()), safe=False)

def vuln_by_severity_v2(request, severity):
if not severity in vulnmap:
return HttpResponseBadRequest('Illegal severity rating.', status=400)

vuln = [reformat_vuln_v2(x.to_dict()) for x in
get_list_or_404(Vulnerability, severity=vulnmap[severity])]
return JsonResponse(vuln, safe=False)

def vuln_by_csname_v2(request, iana_name):
cs = get_object_or_404(CipherSuite, pk=iana_name)
vuln = cs.kex_algorithm.vulnerabilities.all() | \
cs.auth_algorithm.vulnerabilities.all() | \
cs.enc_algorithm.vulnerabilities.all() | \
cs.hash_algorithm.vulnerabilities.all()
result = [reformat_vuln_v2(x.to_dict()) for x in vuln]
return JsonResponse(result, safe=False)
4 changes: 2 additions & 2 deletions directory/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ def __str__(self):
return f"TLS{self.major}.{self.minor}"


class Technology(models.Model):
class Technology(PrintableModel):
class Meta:
abstract=True
ordering=['short_name']
Expand Down Expand Up @@ -460,7 +460,7 @@ class Meta(Technology.Meta):
verbose_name_plural=_('hash algorithms')


class Vulnerability(models.Model):
class Vulnerability(PrintableModel):
class Meta:
ordering=['name']
verbose_name=_('vulnerability')
Expand Down
36 changes: 18 additions & 18 deletions requirements/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
asgiref==3.7.2
brotlipy==0.7.0
certifi==2023.7.22
cffi==1.15.1
certifi==2023.11.17
cffi==1.16.0
chardet==5.2.0
charset-normalizer==3.2.0
coverage==7.3.1
charset-normalizer==3.3.2
coverage==7.3.2
dj-database-url==2.1.0
Django==4.2.5
django-appconf==1.0.5
Django==4.2.7
django-appconf==1.0.6
django-compressor==4.4
django-markdownx==4.0.2
django-otp==1.2.2
django-sass-processor==1.2.2
django-markdownx==4.0.5
django-otp==1.3.0
django-sass-processor==1.3
exceptiongroup==1.1.1
idna==3.4
idna==3.6
importlib-metadata==6.8.0
iniconfig==2.0.0
libsass==0.22.0
lxml==4.9.3
Markdown==3.4.4
packaging==23.1
Pillow==10.0.1
Markdown==3.5.1
packaging==23.2
Pillow==10.1.0
pluggy==1.3.0
psycopg2-binary==2.9.7
psycopg2-binary==2.9.9
pycparser==2.21
pypng==0.20220715.0
pytest==7.4.2
pytest==7.4.3
PyYAML==6.0.1
qrcode==7.4.2
rcssmin==1.1.1
Expand All @@ -34,6 +34,6 @@ rjsmin==1.2.1
sqlparse==0.4.4
tomli==2.0.1
typing_extensions==4.7.1
urllib3==2.0.7
whitenoise==6.5.0
zipp==3.16.2
urllib3==2.1.0
whitenoise==6.6.0
zipp==3.17.0
Loading

0 comments on commit 9599699

Please sign in to comment.