mirror of https://github.com/CIRCL/lookyloo
new: Multiple queries at once on web interface
parent
f17f6f1a37
commit
ee69e66750
|
@ -359,24 +359,17 @@ Flask = ">=0.9"
|
||||||
Six = "*"
|
Six = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "Flask-Login"
|
name = "flask-login"
|
||||||
version = "0.6.0.dev0"
|
version = "0.6.0"
|
||||||
description = "User authentication and session management for Flask."
|
description = "User authentication and session management for Flask."
|
||||||
category = "main"
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
develop = false
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
Flask = ">=1.0.4"
|
Flask = ">=1.0.4"
|
||||||
Werkzeug = ">=1.0.1"
|
Werkzeug = ">=1.0.1"
|
||||||
|
|
||||||
[package.source]
|
|
||||||
type = "git"
|
|
||||||
url = "https://github.com/maxcountryman/flask-login"
|
|
||||||
reference = "main"
|
|
||||||
resolved_reference = "0f94639858946ea8e921743db684b6da97d46385"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flask-restx"
|
name = "flask-restx"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
@ -1530,7 +1523,7 @@ misp = ["python-magic", "pydeep"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "1.1"
|
||||||
python-versions = ">=3.8,<3.11"
|
python-versions = ">=3.8,<3.11"
|
||||||
content-hash = "a1c1bf9772f545beeebf0e22a59bfb19932e4d88f5016744941fec9f5b8770fa"
|
content-hash = "45a1f781fb6065d0091dafc64bbfe2c3512adbdd18dcd20a61ba399302e449ab"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
aiohttp = [
|
aiohttp = [
|
||||||
|
@ -1821,7 +1814,10 @@ flask-cors = [
|
||||||
{file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"},
|
{file = "Flask-Cors-3.0.10.tar.gz", hash = "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"},
|
||||||
{file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"},
|
{file = "Flask_Cors-3.0.10-py2.py3-none-any.whl", hash = "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438"},
|
||||||
]
|
]
|
||||||
Flask-Login = []
|
flask-login = [
|
||||||
|
{file = "Flask-Login-0.6.0.tar.gz", hash = "sha256:aa84fcfb4c3cf09ca58c08e816b7bce73f1349ba1cf13d00d8dffc5872d5fcf6"},
|
||||||
|
{file = "Flask_Login-0.6.0-py3-none-any.whl", hash = "sha256:5cb01ce4dc253967b6ac722a11e46de83b6272ef7a19cc7b5725ae636916d04d"},
|
||||||
|
]
|
||||||
flask-restx = [
|
flask-restx = [
|
||||||
{file = "flask-restx-0.5.1.tar.gz", hash = "sha256:63c69a61999a34f1774eaccc6fc8c7f504b1aad7d56a8ec672264e52d9ac05f4"},
|
{file = "flask-restx-0.5.1.tar.gz", hash = "sha256:63c69a61999a34f1774eaccc6fc8c7f504b1aad7d56a8ec672264e52d9ac05f4"},
|
||||||
{file = "flask_restx-0.5.1-py2.py3-none-any.whl", hash = "sha256:96157547acaa8892adcefd8c60abf9040212ac2a8634937a82946e07b46147fd"},
|
{file = "flask_restx-0.5.1-py2.py3-none-any.whl", hash = "sha256:96157547acaa8892adcefd8c60abf9040212ac2a8634937a82946e07b46147fd"},
|
||||||
|
|
|
@ -65,7 +65,7 @@ Flask-Cors = "^3.0.10"
|
||||||
pyhashlookup = "^1.1.1"
|
pyhashlookup = "^1.1.1"
|
||||||
lief = "^0.12.0"
|
lief = "^0.12.0"
|
||||||
ua-parser = "^0.10.0"
|
ua-parser = "^0.10.0"
|
||||||
flask-login = {git = "https://github.com/maxcountryman/flask-login", rev = "main"}
|
Flask-Login = "^0.6.0"
|
||||||
|
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
misp = ['python-magic', 'pydeep']
|
misp = ['python-magic', 'pydeep']
|
||||||
|
|
|
@ -837,8 +837,8 @@ def capture_web():
|
||||||
else:
|
else:
|
||||||
user = src_request_ip(request)
|
user = src_request_ip(request)
|
||||||
|
|
||||||
if request.method == 'POST' and request.form.get('url'):
|
if request.method == 'POST' and (request.form.get('url') or request.form.get('urls')):
|
||||||
capture_query: Dict[str, Union[str, bytes, int, bool]] = {'url': request.form['url']}
|
capture_query: Dict[str, Union[str, bytes, int, bool]] = {}
|
||||||
# check if the post request has the file part
|
# check if the post request has the file part
|
||||||
if 'cookies' in request.files and request.files['cookies'].filename:
|
if 'cookies' in request.files and request.files['cookies'].filename:
|
||||||
capture_query['cookies'] = request.files['cookies'].stream.read()
|
capture_query['cookies'] = request.files['cookies'].stream.read()
|
||||||
|
@ -875,9 +875,21 @@ def capture_web():
|
||||||
else:
|
else:
|
||||||
flash('Invalid proxy: Check that you entered a scheme, a hostname and a port.', 'error')
|
flash('Invalid proxy: Check that you entered a scheme, a hostname and a port.', 'error')
|
||||||
|
|
||||||
perma_uuid = lookyloo.enqueue_capture(capture_query, source='web', user=user, authenticated=flask_login.current_user.is_authenticated)
|
if request.form.get('url'):
|
||||||
time.sleep(2)
|
capture_query['url'] = request.form['url']
|
||||||
return redirect(url_for('tree', tree_uuid=perma_uuid))
|
perma_uuid = lookyloo.enqueue_capture(capture_query, source='web', user=user, authenticated=flask_login.current_user.is_authenticated)
|
||||||
|
time.sleep(2)
|
||||||
|
return redirect(url_for('tree', tree_uuid=perma_uuid))
|
||||||
|
else:
|
||||||
|
# bulk query
|
||||||
|
bulk_captures = []
|
||||||
|
for url in request.form['urls'].split('\n'):
|
||||||
|
query = capture_query.copy()
|
||||||
|
query['url'] = url
|
||||||
|
new_capture_uuid = lookyloo.enqueue_capture(query, source='web', user=user, authenticated=flask_login.current_user.is_authenticated)
|
||||||
|
bulk_captures.append((new_capture_uuid, url))
|
||||||
|
|
||||||
|
return render_template('bulk_captures.html', bulk_captures=bulk_captures)
|
||||||
elif request.method == 'GET' and request.args.get('url'):
|
elif request.method == 'GET' and request.args.get('url'):
|
||||||
url = unquote_plus(request.args['url']).strip()
|
url = unquote_plus(request.args['url']).strip()
|
||||||
capture_query = {'url': url}
|
capture_query = {'url': url}
|
||||||
|
|
|
@ -38,12 +38,20 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-3">
|
|
||||||
|
<div class="row input-group mb-3">
|
||||||
<label for="url" class="col-sm-1 col-form-label">URL:</label>
|
<label for="url" class="col-sm-1 col-form-label">URL:</label>
|
||||||
<div class="col-sm-10">
|
<input type="text" class="form-control col-auto" name="url" id=singleCaptureField
|
||||||
<input type="text" class="form-control" name="url" id=url
|
placeholder="URL to capture" value="{{predefined_url_to_capture}}" required>
|
||||||
placeholder="URL to capture" value="{{predefined_url_to_capture}}" required>
|
<textarea class="form-control col-auto d-none" placeholder="URLs to capture, one per line"
|
||||||
</div>
|
name="urls" id=multipleCapturesField></textarea>
|
||||||
|
<span class="col-sm-2 input-group-text">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" name="multipleCaptures" id="multipleCaptures" type="checkbox"
|
||||||
|
value="" aria-label="tick to enable multiple captures">
|
||||||
|
<label for="multipleCaptures" class="form-check-label">Multiple captures</label>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -208,4 +216,23 @@
|
||||||
<script src='{{ url_for('static', filename='capture.js') }}'
|
<script src='{{ url_for('static', filename='capture.js') }}'
|
||||||
integrity="{{get_sri('static', 'capture.js')}}"
|
integrity="{{get_sri('static', 'capture.js')}}"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$('#multipleCaptures').on('click', function(e) {
|
||||||
|
if (document.getElementById('multipleCaptures').checked == true) {
|
||||||
|
document.getElementById('singleCaptureField').value = '';
|
||||||
|
$("#singleCaptureField").addClass("d-none");
|
||||||
|
$("#singleCaptureField").removeAttr("required");
|
||||||
|
$("#multipleCapturesField").removeClass("d-none");
|
||||||
|
$("#multipleCapturesField").attr("required", true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.getElementById('multipleCapturesField').value = '';
|
||||||
|
$("#singleCaptureField").removeClass("d-none");
|
||||||
|
$("#singleCaptureField").attr("required", true);
|
||||||
|
$("#multipleCapturesField").addClass("d-none");
|
||||||
|
$("#multipleCapturesField").removeAttr("required");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in New Issue