views: add client search to scopes

Add a view to search clients by IP or MAC.

Adapt parse_scopes_from_tree() to include the path of the scope
in the tree.
master
Alejandro Sirgo Rica 2025-01-21 13:21:47 +01:00
parent 655ffbc0bb
commit dd4b7ad229
3 changed files with 111 additions and 2 deletions

View File

@ -0,0 +1,88 @@
{% extends 'scopes.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% import "macros.html" as macros %}
{% set btn_back = true %}
{% block nav_client %} active {% endblock %}
{% block nav_client_search %} active {% endblock %}
{% block content %}
<h2 class="mx-5 subhead-heading">
{{ _('Search clients') }}
</h2>
<div class="mx-5 my-3">
<label for="name-filter">{{ _('Name') }}</label>
<input type="text" id="name-filter" class="form-control mb-2">
<label for="ip-filter">{{ _('IP Address') }}</label>
<input type="text" id="ip-filter" class="form-control mb-2">
<label for="mac-filter">{{ _('MAC') }}</label>
<input type="text" id="mac-filter" class="form-control mb-2">
<button id="search-button" class="btn btn-primary">{{ _('Search') }}</button>
</div>
<div id="clients-container" class="mx-5 mt-3"></div>
<script>
let clients = {{ clients|tojson|safe }};
function renderClients(data) {
const container = document.getElementById('clients-container');
container.innerHTML = '';
let currentPath = null;
let ul = null;
data.forEach(client => {
if (client.tree_path !== currentPath) {
currentPath = client.tree_path;
const pathElement = document.createElement('p');
pathElement.innerHTML = `<strong>${currentPath}</strong>:`;
container.appendChild(pathElement);
ul = document.createElement('ul');
container.appendChild(ul);
}
const li = document.createElement('li');
li.textContent = `${client.name} (IP: ${client.ip.join(', ')} | MAC: ${client.mac})`;
ul.appendChild(li);
});
}
function filterClients() {
const nameFilter = document.getElementById('name-filter').value.toLowerCase();
const ipFilter = document.getElementById('ip-filter').value;
const macFilter = document.getElementById('mac-filter').value;
const filtered = clients.filter(client => {
const matchesName = nameFilter ? client.name.toLowerCase().includes(nameFilter) : true;
const matchesIP = ipFilter ? client.ip.some(ip => ip.includes(ipFilter)) : true;
const matchesMAC = macFilter ? client.mac.includes(macFilter) : true;
return matchesName && matchesIP && matchesMAC;
});
renderClients(filtered);
}
renderClients(clients);
document.getElementById('search-button').addEventListener('click', filterClients);
// Search on Enter key press
document.querySelectorAll('#name-filter, #ip-filter, #mac-filter').forEach(input => {
input.addEventListener('keydown', event => {
if (event.key === 'Enter') {
event.preventDefault();
filterClients();
}
});
});
</script>
{% endblock %}

View File

@ -42,6 +42,8 @@
<input class="btn btn-light dropdown-item {% block nav_client_delete %}{% endblock %}" type="submit" value="{{ _('Delete client') }}"
form="scopesForm" formaction="{{ url_for('action_client_delete') }}" formmethod="get">
{% endif %}
<input class="btn btn-light dropdown-item {% block nav_client_search %}{% endblock %}" type="submit" value="{{ _('Search client') }}"
form="scopesForm" formaction="{{ url_for('action_client_search') }}" formmethod="get">
</div>
</div>
{% endif %}

View File

@ -246,15 +246,17 @@ def get_all_repositories():
return data
def parse_scopes_from_tree(tree, scope_type):
def parse_scopes_from_tree(tree, scope_type, tree_path=''):
scopes = []
for scope in tree['scope']:
if scope['type'] == scope_type:
if 'name' in tree:
scope['parent'] = tree['name']
scope['tree_path'] = tree_path
scopes.append(scope)
else:
scopes += parse_scopes_from_tree(scope, scope_type)
new_tree_path = f'{tree_path}{scope.get("name")}/'
scopes += parse_scopes_from_tree(scope, scope_type, new_tree_path)
return scopes
def add_state_and_ips(scope, clients, ips):
@ -1998,6 +2000,23 @@ def action_client_delete():
else:
return redirect(url_for('scopes'))
@app.route('/action/client/search', methods=['GET'])
@handle_server_errors('scopes')
@login_required
def action_client_search():
scopes, clients = get_scopes()
clients = parse_scopes_from_tree(scopes, 'computer')
for client in clients:
payload = {'client': [client['ip'][0]]}
info_response = multi_request('get', '/client/info', payload)
for res in info_response:
mac = res['json']['mac'].lower()
client['mac'] = mac
return render_template('actions/client_search.html',
scopes=scopes,
clients=clients)
@app.route('/action/cmd/run', methods=['GET', 'POST'])
@handle_server_errors('commands')
@login_required