Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions web/apiv2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_safe
from rest_framework.decorators import api_view
try:
from apikey.authentication import ApiKeyAuthentication
except ImportError:
ApiKeyAuthentication = None
from rest_framework.response import Response

sys.path.append(settings.CUCKOO_PATH)
Expand Down Expand Up @@ -1126,6 +1130,8 @@ def tasks_delete(request, task_id, status=False):
return Response(resp)


# Re-enable session-cookie auth so the in-browser "End Session" button works
# under SSO deployments where the global DRF chain is API-key-only.
@csrf_exempt
@api_view(["GET", "POST"])
def tasks_status(request, task_id):
Expand Down
47 changes: 27 additions & 20 deletions web/guac/templates/guac/error.html
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
{% load static %}
<!DOCTYPE html>
<html>
<html class="datatable-dark" lang="en">
<head>
<link rel="icon" href="{% static 'img/cape.png' %}">
<meta charset="utf-8"/>
<title>Guacamole Console</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guacamole Console · CAPE Sandbox</title>
<link rel="icon" type="image/png" href="{% static 'img/cape.png' %}">
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/style.css' %}" rel="stylesheet">
<link href="{% static 'css/atlas.css' %}" rel="stylesheet">
<link href="{% static 'css/all.min.css' %}" rel="stylesheet">
<script src="{% static 'js/jquery.js' %}"></script>
</head>
<body>
{% block content %}
<div class="alert alert-secondary">
<h4>Error</h4>
<p>{{error_msg}}</p>
<script>
switch ('{{error}}') {
case 'remote session':
var task_url = location.origin + 'submit/status/{{task_id}}';
break;
}
document.getElementById("taskStatus").addEventListener("click", function() {
location.replace(task_url);
}, false);
</script>
<body class="bg-dark text-white">
{% include "header.html" %}
<div class="container mt-5">
Comment on lines +13 to +17
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card bg-dark border-danger text-center py-4">
<div class="card-body">
<i class="fas fa-exclamation-circle fa-3x text-danger mb-3"></i>
<h4 class="text-white mb-2">Session Error</h4>
<p class="text-secondary mb-4">{{ error_msg }}</p>
<a href="/submit/status/{{ task_id }}/" class="btn btn-outline-secondary">
<i class="fas fa-tasks me-1"></i>View Task
</a>
</div>
</div>
</div>
</div>
{% endblock %}
</div>
</body>
</html>
</html>
93 changes: 51 additions & 42 deletions web/guac/templates/guac/index.html
Original file line number Diff line number Diff line change
@@ -1,42 +1,51 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="icon" href="{% static 'img/cape.png' %}">
<link href="{% static 'css/guac-main.css' %}" rel="stylesheet" type="text/css"/>
<script src="{% static 'js/crypto-js.min.js' %}"></script>
<script src="{% static 'js/guac-main.js' %}"></script>
<script src="{% static 'js/guacamole-1.4.0-all.min.js' %}"></script>
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/jquery-ui.min.js' %}"></script>
<meta charset="utf-8"/>
<title>Guacamole Console</title>
</head>
<body>
<div class="guaconsole">
<div>
<button id="stopTask">End Session</button>
</div>
<div id="container">
<div id="terminal"></div>
</div>
<div class="dialog" id="launch_error">
<div class="inner">
<p class="message"></p>
<p class="error_msg"></p>
<button type="button" id="taskStatus">View Task</button>
</div>
</div>
<script>
document.getElementById("stopTask").addEventListener("click", function () {
stopTask("{{task_id}}");
});
var task_url = location.origin + '/submit/status/{{task_id}}/'
document.getElementById("taskStatus").addEventListener("click", function() {
location.replace(task_url);
}, false);
GuacMe("html", "{{session_id}}", "{{recording_name}}");
</script>
</div>
</body>
</html>
{% load static %}
<!DOCTYPE html>
<html class="datatable-dark" lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guacamole Console · CAPE Sandbox</title>
<link rel="icon" type="image/png" href="{% static 'img/cape.png' %}">
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/style.css' %}" rel="stylesheet">
<link href="{% static 'css/all.min.css' %}" rel="stylesheet">
<link href="{% static 'css/guac-main.css' %}" rel="stylesheet">
<script src="{% static 'js/crypto-js.min.js' %}"></script>
<script src="{% static 'js/guac-main.js' %}"></script>
<script src="{% static 'js/guacamole-1.4.0-all.min.js' %}"></script>
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/jquery-ui.min.js' %}"></script>
</head>
<body class="bg-dark text-white" style="margin:0;padding:0;overflow:hidden;">
<div class="guaconsole">
<div id="guac-toolbar" class="d-flex align-items-center px-3 py-1 border-bottom border-secondary bg-dark" style="height:42px;flex-shrink:0;">
<a href="/" class="navbar-brand py-0 me-3">
<img src="{% static 'graphic/cape.png' %}" height="28" alt="CAPE Sandbox">
</a>
<span class="text-secondary me-2 small">|</span>
<span class="text-secondary small me-1">Task</span>
<a href="/submit/status/{{ task_id }}/" class="text-info small me-auto text-decoration-none">#{{ task_id }}</a>
<button id="stopTask" class="btn btn-sm btn-outline-danger">
<i class="fas fa-stop-circle me-1"></i>End Session
</button>
</div>
<div id="container">
<div id="terminal"></div>
<div id="launch_error" style="display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);z-index:1002;max-width:440px;width:100%;">
<div style="background:#212529;border:1px solid #495057;border-radius:8px;padding:20px;box-shadow:0 0 30px rgba(0,0,0,0.8);color:#fff;">
<h6 id="dialog-heading" class="mb-2" style="color:#fff;"><i class="fas fa-exclamation-triangle me-1 text-danger"></i>Session Error</h6>
<p class="message mb-1 small" style="color:#adb5bd;"></p>
<p class="error_msg mb-2 small" style="color:#6c757d;"></p>
<a id="taskStatus" href="/submit/status/{{ task_id }}/" class="btn btn-sm btn-outline-light"><i class="fas fa-tasks me-1"></i>View Task</a>
</div>
</div>
</div>
</div>
<script>
document.getElementById("stopTask").addEventListener("click", function() {
stopTask("{{ task_id }}");
});
GuacMe("html", "{{ session_id }}", "{{ recording_name }}");
</script>
</body>
</html>
81 changes: 48 additions & 33 deletions web/guac/templates/guac/wait.html
Original file line number Diff line number Diff line change
@@ -1,33 +1,48 @@
{% load static %}
<!DOCTYPE html>
<html>
<head>
<link rel="icon" href="{% static 'img/cape.png' %}">
<script src="{% static 'js/jquery.js' %}"></script>
<script src="{% static 'js/jquery-ui.min.js' %}"></script>
<meta charset="utf-8"/>
<title>Guacamole Console</title>
</head>
<body>
{% block content %}
<div class="alert alert-secondary">
<h4>Hang on...</h4>
<p>The VM is not running, yet. This page will refresh every 5 seconds.</p>
<div class="progress progress-striped active" style="margin-top: 10px;"></div>
<button type="button" id="taskStatus">View Task</button>
<script>
var task_url = location.origin + '/submit/status/{{task_id}}/'
document.getElementById("taskStatus").addEventListener("click", function() {
location.replace(task_url);
}, false);
</script>
</div>
<script type="text/JavaScript">
function reloadpage() {
location.reload(true);
}
setTimeout(reloadpage, 5000);
</script>
{% endblock %}
</body>
</html>
{% load static %}
<!DOCTYPE html>
<html class="datatable-dark" lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Guacamole Console · CAPE Sandbox</title>
<link rel="icon" type="image/png" href="{% static 'img/cape.png' %}">
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'css/style.css' %}" rel="stylesheet">
<link href="{% static 'css/atlas.css' %}" rel="stylesheet">
<link href="{% static 'css/all.min.css' %}" rel="stylesheet">
<script src="{% static 'js/jquery.js' %}"></script>
</head>
<body class="bg-dark text-white">

{% include "header.html" %}

Comment on lines +13 to +18
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card bg-dark border-secondary text-center py-5">
<div class="card-body">
<div class="mb-4">
<i class="fas fa-desktop fa-3x text-secondary mb-3"></i>
</div>
<h4 class="text-white mb-2">Hang on...</h4>
<p class="text-secondary mb-4">The VM is not running yet. This page will refresh every 5 seconds.</p>
<div class="progress mb-4" style="height: 4px;">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-danger w-100"></div>
</div>
<button type="button" id="taskStatus" class="btn btn-outline-secondary">
<i class="fas fa-tasks me-1"></i> View Task
</button>
</div>
</div>
</div>
</div>
</div>

<script>
document.getElementById("taskStatus").addEventListener("click", function() {
location.replace(location.origin + '/submit/status/{{ task_id }}/');
});
setTimeout(function() { location.reload(true); }, 5000);
</script>
</body>
</html>
33 changes: 9 additions & 24 deletions web/static/css/guac-main.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,23 @@ html, body {
width: 100%;
}

.dialog,
.error {
max-width: 640px;
background: #fff;
padding: 5px;
border-radius: 8px;
box-shadow: 0 0 10px #000;
text-align: left;
}

/* Error dialog overlay on the canvas */
.dialog {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1002;
max-width: 480px;
width: 100%;
display: none;
}

.inner {
background: rgb(245, 245, 245);
background: #1e1e2e;
border: 1px solid #dc3545;
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.9);
box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.7);
overflow: hidden;
padding: 10px;
position: relative;
}

.dialog {
display: none;
padding: 20px;
box-shadow: 0 0 30px rgba(220, 53, 69, 0.3);
color: #fff;
}

.no-close .ui-dialog-titlebar-close {
display: none
}
39 changes: 30 additions & 9 deletions web/static/js/guac-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,20 @@ function GuacMe(element, session_id, recording_name) {
"The server's error message was:";
var error_message = guac_error.message;

if (guac_error.message.toLowerCase().startsWith('aborted')) {
dialog_message = "Remote session terminated.";
error_message = "Close tab.";
var isNormalEnd = guac_error.message.toLowerCase().startsWith('aborted');
if (isNormalEnd) {
dialog_message = "The analysis session has ended.";
error_message = "";
}
var heading = dialog.find('#dialog-heading');
if (isNormalEnd) {
heading.html('<i class="fas fa-check-circle me-1" style="color:#198754"></i>Session Complete');
} else {
heading.html('<i class="fas fa-exclamation-triangle me-1" style="color:#dc3545"></i>Session Error');
}
dialog.find('.message').html(dialog_message);
dialog.find('.error_msg').html(error_message);
dialog.dialog({dialogClass: 'no-close'});
dialog.dialog(dialog_container);
dialog.css('display', 'block');
};
};

Expand All @@ -169,15 +175,30 @@ function GuacMe(element, session_id, recording_name) {
init();
}

function getCsrfToken() {
var match = document.cookie.match(/csrftoken=([^;]+)/);
return match ? match[1] : '';
}

function stopTask(taskId) {
var apiUrl = location.origin + "/apiv2/tasks/status/" + taskId + "/";
var btn = document.getElementById('stopTask');
if (btn) { btn.disabled = true; btn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i>Stopping...'; }

var apiUrl = location.origin + "/apiv2/tasks/status/" + taskId + "/";
fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCsrfToken(),
},
body: JSON.stringify({ status: 'finish' }),
})
.then(response => response.json())
.then(data => console.log('Response:', data))
.catch(error => console.error('Error:', error));
.then(function(data) {
location.replace(location.origin + '/submit/status/' + taskId + '/');
})
.catch(function(error) {
console.error('Error:', error);
if (btn) { btn.disabled = false; btn.innerHTML = '<i class="fas fa-stop-circle me-1"></i>End Session'; }
});
Comment on lines +187 to +203
}
Loading