first commit from a working website

This commit is contained in:
Joost Agterhoek 2024-08-29 21:03:36 +02:00
parent 2749d06a2d
commit 709d6e2f61
23 changed files with 916 additions and 0 deletions

115
app.py Normal file
View File

@ -0,0 +1,115 @@
# from dotenv import load_dotenv
import secrets
import socket
import uuid
from logging.config import dictConfig
from pprint import pprint
from urllib.parse import urlparse
from flask import Flask, flash, redirect, render_template, request, session, url_for
from markupsafe import escape
# from io import StringIO
from validators import domain, email, ipv4, ipv6, url
from constants import *
from host_lookup import abuseipdb, metadata, spf_dmarc, virustotal_api_test
from upload import csv_parse
# import csv
dictConfig(LOGCONF)
# put this in a .flaskenv file: https://dev.to/kubona_my/dealing-with-environment-variables-in-flask-o1
app = Flask(__name__)
generate_secret = secrets.token_urlsafe(16)
app.secret_key = generate_secret
# app.debug = True
class Info(object):
def __init__(self, host):
self.host = host
self.ip_address = None
self.host_type = metadata.check(self.host)
self.metadata = metadata.lookup(self.host)
self.emailsec = ()
self.vt = {}
self.abuseipdb = {}
def lookup(host):
result = Info(host)
if result.host_type == DOMAIN:
result.ip_address = socket.gethostbyname(host)
result.emailsec = spf_dmarc.lookup(host)
result.vt = virustotal_api_test.analyse(result.host, result.host_type)
result.abuseipdb = abuseipdb.analyse(result.ip_address)
print("[DEBUGGING]")
pprint(result.emailsec)
elif result.host_type == URL:
result.domain = urlparse(host).netloc
result.ip_address = socket.gethostbyname(result.domain)
result.vt = virustotal_api_test.analyse(result.host, result.host_type)
result.abuseipdb = abuseipdb.analyse(result.ip_address)
elif result.host_type == IPV4 or IPV6:
result.vt = virustotal_api_test.analyse(result.host, result.host_type)
result.abuseipdb = abuseipdb.analyse(host)
return result
@app.route("/")
def index():
# logging example taken from https://betterstack.com/community/guides/logging/how-to-start-logging-with-flask/
session["ctx"] = {"request_id": str(uuid.uuid4())}
app.logger.info("A user visited the home page >>> %s", session["ctx"])
return redirect(url_for("lookup"))
# refactor to handle form requests better: https://www.digitalocean.com/community/tutorials/how-to-use-web-forms-in-a-flask-application
@app.route("/lookup", methods=["GET", "POST"])
def lookup():
host = ""
host = escape(request.form.get("host"))
session["ctx"] = {"request_id": str(uuid.uuid4())}
# figure out how to start a session, maybe with a variable?
# variable = session.get('something')
if request.method == "GET":
return render_template("lookup_options.html")
elif request.method == "POST" and "host" in request.form:
host = ""
host = escape(request.form.get("host"))
session["ctx"] = {"request_id": str(uuid.uuid4())}
app.logger.info(
"A user submitted a host to look up. | host: %s >>> %s",
host,
session["ctx"],
)
if not host:
flash("Try again", "error")
return render_template("lookup_options.html")
elif host:
result = Info.lookup(host)
return render_template(
"lookup_options.html",
host=result.host,
host_type=result.host_type,
result=result,
)
elif request.method == "POST" and "file" in request.files:
file = request.files["file"]
extracted = csv_parse.extract(file)
results = []
for host in extracted:
results.append(Info.lookup(host))
print(results)
return render_template("lookup_options.html")
else:
flash("No file!", "error")
return render_template("lookup_options.html")
if __name__ == "__main__":
app.run(debug=True)

26
constants.py Normal file
View File

@ -0,0 +1,26 @@
LOGCONF = {
"version": 1,
"formatters": {
"default": {
"format": "[%(asctime)s] %(levelname)s in %(module)s: %(message)s",
}
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
"formatter": "default",
},
"file": {
"class": "logging.FileHandler",
"filename": "flask.log",
"formatter": "default",
},
},
"root": {"level": "DEBUG", "handlers": ["console", "file"]},
}
URL = "URL"
DOMAIN = "domain"
IPV4 = "IPv4"
IPV6 = "IPv6"

41
host_lookup/abuseipdb.py Normal file
View File

@ -0,0 +1,41 @@
from base64 import decode
import json
import os
import requests
import requests_cache
from dotenv import load_dotenv
from pprint import pprint
class API_error(Exception):
pass
def environment():
requests_cache.install_cache(expire_after=360, allowable_methods=("POST"))
load_dotenv()
api_key = os.getenv("ABUSEIPDB_API")
return api_key
def lookup(api_key, host):
url = "https://api.abuseipdb.com/api/v2/check"
payload = {"ipAddress": "", "maxAgeInDays": "90"}
payload.update({"ipAddress": host})
headers = {"Accept": "application/json", "Key": api_key}
response = requests.request(
method="GET", url=url, params=payload, headers=headers, verify=False
) # TODO: remove SSL verify=False and add signed certificate if possible.
# Figure out how caching functions here: https://requests-cache.readthedocs.io/en/stable/examples.html
print(requests_cache.get_cache())
print("Cached:")
print("\n".join(requests_cache.get_cache().urls()))
return response
def analyse(host):
api_key = environment()
result = lookup(api_key, host)
decoded_result = json.loads(result.text)
return decoded_result

30
host_lookup/metadata.py Normal file
View File

@ -0,0 +1,30 @@
from ipaddress import ip_address
from whois import whois
from ipwhois import IPWhois
import validators
from constants import URL, DOMAIN, IPV4, IPV6
def check(host):
if validators.url(host):
host_type = URL
elif validators.domain(host):
host_type = DOMAIN
elif validators.ip_address.ipv4(host):
host_type = IPV4
elif validators.ip_address.ipv6(host):
host_type = IPV6
return host_type
# def lookup(host_type):
def lookup(host):
result = dict(whois(host))
return result
# result = whois(host_type[1])
# return result, host_type[0]
# obj = IPWhois(host_type[1])
# res = obj.lookup_rdap()
# return res, host_type[0]

3
host_lookup/otx_api.py Normal file
View File

@ -0,0 +1,3 @@
# Try to get historical telemetry like this page shows: https://otx.alienvault.com/indicator/ip/8.8.8.8
# Apparently this API does not provide this information :( f.e. the below curl request does not provide information about historical OTX telemetry.
# curl https://otx.alienvault.com/api/v1/indicators/url/http://www.freputation.com/spreputation_san_ponso/slides/IMG_0068.html/general -H "X-OTX-API-KEY: ec672963e435bb7a09c494534b79a6a7a273a5bde5ea560874cccd72e2bc76fc"

9
host_lookup/parse_URI.py Normal file
View File

@ -0,0 +1,9 @@
# This module should extract any and all URIs (IPs or URLs) from copy and pasted text.
def parse(text):
split_text = text.split()
for URI in split_text:
print(URI)

9
host_lookup/spf_dmarc.py Normal file
View File

@ -0,0 +1,9 @@
from checkdmarc.dmarc import check_dmarc
from checkdmarc.spf import check_spf
import validators
def lookup(host: str) -> tuple:
result_dmarc = check_dmarc(host)
result_spf = check_spf(host)
return (result_dmarc, result_spf)

24
host_lookup/virustotal.py Normal file
View File

@ -0,0 +1,24 @@
import vt
import os
import requests
import virustotal_python
from dotenv import load_dotenv
from pprint import pprint
from base64 import urlsafe_b64encode
# todo: implement my own API request module to then try and cache the response (see -> https://realpython.com/caching-external-api-requests/#requests-cache)
def vt_lookup(URL):
load_dotenv()
api_key = os.getenv("VT_API")
with virustotal_python.Virustotal(api_key) as vtotal:
try:
resp = vtotal.request("urls", data={"url": URL}, method="POST")
print(resp)
# Safe encode URL in base64 format
# https://developers.virustotal.com/reference/url
url_id = urlsafe_b64encode(URL.encode()).decode().strip("=")
report = vtotal.request(f"urls/{url_id}")
return report.data
except virustotal_python.VirustotalError as err:
print(f"Failed to send URL: {URL} for analysis and get the report: {err}")

View File

@ -0,0 +1,77 @@
import json
import os
import requests
from dotenv import load_dotenv
from pprint import pprint
from constants import URL, DOMAIN, IPV4, IPV6
# Would be nice to define some constants, f.e. for the various API urls, the headers, etc.
def environment():
load_dotenv()
api_key = os.getenv("VT_API")
return api_key
# Unfortunately this works for actual URLs, not domains. See: https://docs.virustotal.com/reference/domain-info
# This also doesn't work for IPv6 addresses, where the response_dict does not have a 'data' key. So I would have to revamp this module and make separate functions called based on host type (URL, IPv4 and -6, domain).
def analysis_object(api_key, host):
url = "https://www.virustotal.com/api/v3/urls"
payload = {"url": ""}
payload.update({"url": host})
headers = {
"accept": "application/json",
"content-type": "application/x-www-form-urlencoded",
"x-apikey": api_key,
}
response = requests.post(url, data=payload, headers=headers)
response_dict = json.loads(response.text)
response_id = response_dict["data"]["id"]
return response_id
def analyse_domain(api_key, host):
url = "https://www.virustotal.com/api/v3/domains/" + host
headers = {
"accept": "application/json",
"content-type": "application/x-www-form-urlencoded",
"x-apikey": api_key,
}
analysis_response = requests.get(url, headers=headers)
response_dict = json.loads(analysis_response.text)
# Probably still need to turn the requests.get into a json like below
return response_dict
def analyse_URL(api_key, response_id):
analysis_url = "https://www.virustotal.com/api/v3/analyses/{}".format(response_id)
headers = {"accept": "application/json", "x-apikey": api_key}
analysis_response = requests.get(analysis_url, headers=headers)
analysis_dict = json.loads(analysis_response.text)
# return analysis_response.text
return analysis_dict
def analyse_IP(api_key, host):
analysis_url = "https://www.virustotal.com/api/v3/ip_addresses/{}".format(host)
headers = {"accept": "application/json", "x-apikey": api_key}
analysis_response = requests.get(analysis_url, headers=headers)
analysis_dict = json.loads(analysis_response.text)
# Implement this: https://docs.virustotal.com/reference/ip-info
return analysis_dict
def analyse(host, host_type):
api_key = environment()
if host_type == URL:
response_id = analysis_object(api_key, host)
result = analyse_URL(api_key, response_id)
elif host_type == DOMAIN:
result = analyse_domain(api_key, host)
# elif for IPv4 and IPv6.
elif host_type == IPV4 or IPV6:
result = analyse_IP(api_key, host)
return result

32
requirements.txt Normal file
View File

@ -0,0 +1,32 @@
attrs==24.2.0
blinker==1.8.2
cattrs==24.1.0
certifi==2024.7.4
cffi==1.17.0
charset-normalizer==3.3.2
checkdmarc==5.5.0
click==8.1.7
cryptography==43.0.0
dnspython==2.0.0
expiringdict==1.2.2
Flask==3.0.3
idna==3.8
ipwhois==1.2.0
itsdangerous==2.2.0
Jinja2==3.1.4
MarkupSafe==2.1.5
platformdirs==4.2.2
publicsuffixlist==1.0.2.20240827
pycparser==2.22
pyleri==1.4.3
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
python-whois==0.9.4
requests==2.32.3
requests-cache==1.2.1
six==1.16.0
timeout-decorator==0.5.0
url-normalize==1.4.3
urllib3==2.2.2
validators==0.33.0
Werkzeug==3.0.4

6
static/styles/style.css Normal file
View File

@ -0,0 +1,6 @@
.host_form {
text-align: center;
}
.upload_form {
text-align: center;
}

3
style.css Normal file
View File

@ -0,0 +1,3 @@
h1 {
color: red;
}

103
templates/IPv4.html Normal file
View File

@ -0,0 +1,103 @@
{% if result %}
<div>
<table id="data" class="table table-striped">
<thead>
<tr>
<th>IP resolves to URL</th>
<th>creation date</th>
<th>registrar</th>
<th>registrar's country of residence</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.metadata['domain_name'] }}</td>
<td>{{ result.metadata['creation_date'] }}</td>
<td>{{ result.metadata['registrar'] }}</td>
<td>{{ result.metadata['country'] }}</td>
</tr>
</tbody>
</table>
<table id="virustotal_stats" class="table table-striped">
<thead>
<tr>
<th>Malicious</th>
<th>Suspicious</th>
<th>Undetected</th>
<th>Harmless</th>
<th>Timeout</th>
</tr>
</thead>
<tbody>
<tr>
<td>
{{
result.vt['data']['attributes']['last_analysis_stats']['malicious']}}
</td>
<td>
{{
result.vt['data']['attributes']['last_analysis_stats']['suspicious']
}}
</td>
<td>
{{
result.vt['data']['attributes']['last_analysis_stats']['undetected']
}}
</td>
<td>
{{ result.vt['data']['attributes']['last_analysis_stats']['harmless']
}}
</td>
<td>
{{ result.vt['data']['attributes']['last_analysis_stats']['timeout']
}}
</td>
</tr>
</tbody>
</table>
<table id="virustotal_all_vendors" class="table table-striped">
<thead>
<tr>
<th>Vendor name</th>
<th>Results</th>
</tr>
</thead>
<tbody>
{% for vendor,value in
result.vt['data']['attributes']['last_analysis_results'].items() %}
<tr>
<td>{{ vendor }}</td>
<td>{{ value['result'] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="abuseipdb" class="table table-striped">
<thead>
<tr>
<th>Abuse IPDB confidence score</th>
<th>Total reports</th>
<th>Last reported</th>
<th>Tor or not</th>
<th>Hostnames</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.abuseipdb.data.abuseConfidenceScore }}</td>
<td>{{ result.abuseipdb.data.totalReports }}</td>
<td>{{ result.abuseipdb.data.lastReportedAt }}</td>
<td>{{ result.abuseipdb.data.isTor }}</td>
<td>{{result.abuseipdb.data.hostnames }}</td>
</tr>
</tbody>
</table>
</div>
{% elif results %}
<div>
<p>VISUALIZE</p>
</div>
{% endif %}

80
templates/URL.html Normal file
View File

@ -0,0 +1,80 @@
{% if result %}
<div>
<table id="data" class="table table-striped">
<thead>
<tr>
<th>domain</th>
<th>creation date</th>
<th>registrar</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.metadata['domain_name'] }}</td>
<td>{{ result.metadata['creation_date'] }}</td>
<td>{{ result.metadata['registrar'] }}</td>
</tr>
</tbody>
</table>
<table id="virustotal_stats" class="table table-striped">
<thead>
<tr>
<th>Malicious</th>
<th>Suspicous</th>
<th>Undetected</th>
<th>Harmless</th>
<th>Timeout</th>
</tr>
</thead>
<tbody>
<tr>
{% for value in result.vt.data.attributes.stats.values() %}
<td>{{ value }}</td>
{% endfor %}
</tr>
</tbody>
</table>
<table id="virustotal_all_vendors" class="table table-striped">
<thead>
<tr>
<th>Vendor name</th>
<th>Results</th>
</tr>
</thead>
<tbody>
{% for value in result.vt.data.attributes.results.values() if value.result == 'malicious' or value.result == 'malware' %}
<tr>
<td>{{ value.engine_name }}</td>
<td>{{ value.result }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="abuseipdb" class="table table-striped">
<thead>
<tr>
<th>Abuse IPDB confidence score</th>
<th>Total reports</th>
<th>Last reported</th>
<th>Tor or not</th>
<th>Hostnames</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.abuseipdb.data.abuseConfidenceScore }}</td>
<td>{{ result.abuseipdb.data.totalReports }}</td>
<td>{{ result.abuseipdb.data.lastReportedAt }}</td>
<td>{{ result.abuseipdb.data.isTor }}</td>
<td>{{result.abuseipdb.data.hostnames }}</td>
</tr>
</tbody>
</table>
</div>
{% elif results %}
<div>
<p>VISUALIZE</p>
</div>
{% endif %}

109
templates/domain.html Normal file
View File

@ -0,0 +1,109 @@
{% if result %}
<div>
<p>domain</p>
<table id="data" class="table table-striped">
<thead>
<tr>
<th>URL</th>
<th>creation date</th>
<th>registrar</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.metadata['domain_name'] }}</td>
<td>{{ result.metadata['creation_date'] }}</td>
<td>{{ result.metadata['registrar'] }}</td>
</tr>
</tbody>
</table>
<table id="spf_dmarc" class="table table-striped">
<thead>
<tr>
<th>DMARC record</th>
<th>DMARC validity</th>
<th>SPF record</th>
<th>SPF validity</th>
<th>SPF keys()</th>
<th>SPF dns lookups</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.emailsec[0]['record'] }}</td>
<td>{{ result.emailsec[0]['valid'] }}</td>
<td>{{ result.emailsec[1]['record'] }}</td>
<td>{{ result.emailsec[1]['valid'] }}</td>
<td>{{ result.emailsec[1].keys() }}</td>
{% for item in result.emailsec[1]['parsed']%}
<td>{{ item }}</td>
{% endfor %}
</tr>
</tbody>
</table>
<table id="virustotal_stats" class="table table-striped">
<thead>
<tr>
<th>Malicious</th>
<th>Suspicous</th>
<th>Undetected</th>
<th>Harmless</th>
<th>Timeout</th>
</tr>
</thead>
<tbody>
<tr>
{% for value in result.vt.data.attributes.last_analysis_stats.values()
%}
<td>{{ value }}</td>
{% endfor %}
</tr>
</tbody>
</table>
<table id="virustotal_all_vendors" class="table table-striped">
<thead>
<tr>
<th>Vendor name</th>
<th>Results</th>
</tr>
</thead>
<tbody>
{% for value in result.vt.data.attributes.last_analysis_results.values()
%}
<tr>
<td>{{ value.engine_name }}</td>
<td>{{ value.result }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table id="abuseipdb" class="table table-striped">
<thead>
<tr>
<th>Abuse IPDB confidence score</th>
<th>Total reports</th>
<th>Last reported</th>
<th>Tor or not</th>
<th>Hostnames</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ result.abuseipdb.data.abuseConfidenceScore }}</td>
<td>{{ result.abuseipdb.data.totalReports }}</td>
<td>{{ result.abuseipdb.data.lastReportedAt }}</td>
<td>{{ result.abuseipdb.data.isTor }}</td>
<td>{{result.abuseipdb.data.hostnames }}</td>
</tr>
</tbody>
</table>
</div>
{% elif results %}
<div>
<p>VISUALIZE</p>
</div>
{% endif %}

View File

@ -0,0 +1,8 @@
{% with messages=get_flashed_messages() %} {% if messages %}
<p class="text-center">
{% for message in messages %}
<i class="fa-solid fa-circle-exclamation"></i>
{{message}}
<i class="fa-solid fa-circle-exclamation"></i>
{% endfor %} {% endif %} {% endwith %}
</p>

1
templates/index.html Normal file
View File

@ -0,0 +1 @@
TESTIE

48
templates/layout.html Normal file
View File

@ -0,0 +1,48 @@
<!doctype html>
<html>
<head>
<title>Got something to look up? I got you!</title>
<link
rel="stylesheet"
type="text/css"
href="https://use.fontawesome.com/releases/v6.5.1/css/all.css"
/>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x"
crossorigin="anonymous"
/>
<link
rel="stylesheet"
type="text/css"
href="https://cdn.datatables.net/1.10.25/css/dataTables.bootstrap5.css"
/>
<link
rel="stylesheet"
type="text/css"
href="{{ url_for('static', filename='styles/style.css')}}"
/>
</head>
<body>
{% block content %} {% endblock %}
<script
type="text/javascript"
charset="utf8"
src="https://code.jquery.com/jquery-3.6.0.min.js"
></script>
<script
type="text/javascript"
charset="utf8"
src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.js"
></script>
<script
type="text/javascript"
charset="utf8"
src="https://cdn.datatables.net/1.10.25/js/dataTables.bootstrap5.js"
></script>
{% block scripts %}{% endblock %}
</body>
</html>

View File

@ -0,0 +1,97 @@
{% extends "layout.html" %}
{% block content %}
<h1 class="text-center">URL or IP lookup</h1>
<div class="host_form">
<form host="/lookup" method="POST">
<input type="text" name="host">
<input type="SUBMIT" value="Type it in">
</form>
<p>OR</p>
<form action="/lookup" host="/lookup" method="POST" enctype="multipart/form-data">
<input type="file" name="file">
<input type="SUBMIT" value="Upload a csv">
</form>
</div>
{% if host_type == "domain" %}
{% include "domain.html" %}
{% elif host_type == "URL" %}
{% include "URL.html" %}
{% elif host_type == "IPv4" %}
{% include "IPv4.html" %}
{% elif host_type == "IPv6" %}
{% include "IPv6.html" %}
{% else %}
<p class="text-center">Copy paste your URLs or IPs and press submit!</p>
{% include "empty_form.html" %}
{% endif %}
{% endblock %}
{% block scripts %}
<script>
$(document).ready(function () {
$('#virustotal_all_vendors').DataTable({
scrollY: 300,
<!-- scrollX: 100, -->
paging: false,
searching: false,
info: false,
});
});
$(document).ready(function () {
$('#abuseipdb').DataTable({
paging: false,
searching: false,
info: false
});
});
$(document).ready(function () {
$('#data').DataTable({
paging: false,
searching: false,
info: false
});
});
$(document).ready(function () {
$('#virustotal_stats').DataTable({
paging: false,
searching: false,
info: false,
columnDefs: [ {
targets: '_all',
createdCell: function (td, cellData, rowData, row, col) {
if (cellData > 0 && col == 0) {
$(td).css({'background-color':'red','color':'white'});
}
if (cellData > 0 && col == 1) {
$(td).css({'background-color':'orange','color':'white'});
}
if (cellData > 0 && col == 2) {
$(td).css({'background-color':'grey','color':'white'});
}
if (cellData > 0 && col == 3) {
$(td).css({'background-color':'green','color':'white'});
}
},
}
]
})
});
/// Trying out some more cellData searching, this time adding some text
</script>
{% endblock %}

View File

@ -0,0 +1,58 @@
{% extends "layout.html" %}
{% block content %}
<h1>Results!</h1>
<p>What you looked up:</p>
<ul>
<li>URL or IP: {{ URI_type }} </li>
</ul>
<table id="data" class="table table-striped">
<thead>
<tr>
<th>URL</th>
<th>creation date</th>
<th>registrar</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ looked_up.domain_name }}</td>
<td>{{ looked_up.creation_date }}</td>
<td>{{ looked_up.registrar }}</td>
</tr>
</tbody>
</table>
<table id="virustotal_all_vendors" class="table table-striped">
<thead>
<tr>
<th>Vendor name</th>
<th>Results</th>
</tr>
</thead>
<tbody>
{% for value in virustotal_results.attributes.last_analysis_results.values() %}
<tr>
<td>{{ value.engine_name }}</td>
<td>{{ value.result }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{# Below JavaScript table magic from: https://blog.miguelgrinberg.com/post/beautiful-interactive-tables-for-your-flask-templates #}
{% block scripts %}
<script>
$(document).ready(function () {
$('#virustotal_all_vendors').DataTable();
});
</script>
{% endblock %}

15
templates/test.html Normal file
View File

@ -0,0 +1,15 @@
<table id="test" class="table table-striped">
<thead>
<tr>
<th>domain</th>
<th>creation date</th>
<th>registrar</th>
</thead>
<tbody>
<tr>
<td>{{ results.metadata['domain_name'] }}</td>
<td>{{ results.metadata['creation_date'] }}</td>
<td>{{ results.metadata['registrar'] }}</td>
</tr>
</tbody>
</table>

0
templates/upload.html~ Normal file
View File

22
upload/csv_parse.py Normal file
View File

@ -0,0 +1,22 @@
import csv
from io import StringIO
from validators import ipv4, ipv6, url, domain
def extract(uploaded):
hosts = []
content = uploaded.read()
decoded = content.decode("utf-8")
file = StringIO(decoded)
csv_data = csv.reader(file, delimiter=",")
for row in csv_data:
for value in row:
if url(value):
hosts.append(value)
elif domain(value):
hosts.append(value)
elif ipv4(value):
hosts.append(value)
elif ipv6(value):
hosts.append(value)
return hosts