2 Commits

Author SHA1 Message Date
379fef4b00 Improved copiable fields 2024-09-11 17:22:12 +02:00
bdba6db42d Add support for backfillips 2024-09-10 11:51:53 +02:00
7 changed files with 71 additions and 12 deletions

View File

@@ -118,3 +118,15 @@ i.disabled {
span.expired { span.expired {
color: #888; color: #888;
} }
.copy:hover {
transform: scale(1.5, 1.5);
-ms-transform: scale(1.5, 1.5)); /* IE 9 */
-webkit-transform: scale(1.5, 1.5);
}
.copy:hover::after {
content: "📄 click to copy";
font-size: 80%;
/* font-style:oblique; */
font-family: monospace;
}

View File

@@ -14,12 +14,10 @@ function renameNode(nodeId) {
} }
function createPKA(username) { function createPKA(username) {
console.log(username);
var url = `${username}/pakcreate`; var url = `${username}/pakcreate`;
var ephemereal = $("#ephemereal").is(":checked"); var ephemereal = $("#ephemereal").is(":checked");
var reusable = $("#reusable").is(":checked"); var reusable = $("#reusable").is(":checked");
var expiration = $("#expiration").val(); var expiration = $("#expiration").val();
console.log(expiration);
$.ajax({ $.ajax({
url: url, url: url,
method: "POST", method: "POST",
@@ -65,3 +63,29 @@ function toggleExpired(obj) {
$(".pka-expired").addClass("pka-hide"); $(".pka-expired").addClass("pka-hide");
} }
} }
function backfillips(obj) {
var url = "backfillips";
var button = $(obj);
var original = button.html();
$.ajax({
url: url,
method: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
xhrFields: {
withCredentials: true,
},
data: {},
success: function (data) {
if (data.length) {
button.html("Updated");
} else {
button.html("Done");
}
setTimeout(function () {
button.html(original);
}, 500);
},
});
}

View File

@@ -76,11 +76,11 @@
<h5>addresses</h5> <h5>addresses</h5>
{% for ip in node.ipAddresses %} {% for ip in node.ipAddresses %}
<div class="row data"> <div class="row data">
<div class="col col-3"> <div class="col col-6">
<span class="address copy" <span class="address copy"
value="{{ ip }}"> value="{{ ip }}">
{{ ip }} {{ ip }}
</spanundefined> </span>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@@ -132,7 +132,9 @@
<strong>machineKey</strong> <strong>machineKey</strong>
</div> </div>
<div class="col col-8 float-left"> <div class="col col-8 float-left">
<code>{{ node.machineKey }}</code> <span class="copy" value="{{ node.machineKey }}">
<code>{{ node.machineKey }}</code>
</span>
</div> </div>
</div> </div>
@@ -141,7 +143,9 @@
<strong>nodeKey</strong> <strong>nodeKey</strong>
</div> </div>
<div class="col col-8 float-left"> <div class="col col-8 float-left">
<code>{{ node.nodeKey }}</code> <span class="copy" value="{{ node.nodeKey }}">
<code>{{ node.nodeKey }}</code>
</span>
</div> </div>
</div> </div>
@@ -150,7 +154,9 @@
<strong>discoKey</strong> <strong>discoKey</strong>
</div> </div>
<div class="col col-8 float-left"> <div class="col col-8 float-left">
<span class="copy" value="{{ node.discoKey }}">
<code>{{ node.discoKey }}</code> <code>{{ node.discoKey }}</code>
</span>
</div> </div>
</div> </div>
<p></p> <p></p>
@@ -220,7 +226,7 @@
{% block scripts %} {% block scripts %}
<script> <script>
$(function () { $(function () {
$('.address.copy').on('click', function() { $('.copy').on('click', function() {
copyToClipboard(this) copyToClipboard(this)
}) })
}) })

View File

@@ -1,7 +1,16 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<h3>nodes</h3> <div class="row data justify-content-between">
<div class="col col-4">
<h3>nodes</h3>
</div>
<div class="col col-2">
<span data-toggle="tooltip" data-placement="right" title="Recheck all IP addresses of all nodes">
<button type="button" class="btn btn-outline-primary btn-sm" onClick="backfillips(this);">Backfill IP addresses</button>
</span>
</div>
</div>
<hr> <hr>
<p></p> <p></p>
<table id="nodes" class="display" style="width:100%"> <table id="nodes" class="display" style="width:100%">

View File

@@ -9,6 +9,7 @@ from flask import jsonify
from hsapi_client import Node, User, Route, PreAuthKey from hsapi_client import Node, User, Route, PreAuthKey
from hsapi_client.preauthkeys import (v1CreatePreAuthKeyRequest, from hsapi_client.preauthkeys import (v1CreatePreAuthKeyRequest,
v1ExpirePreAuthKeyRequest) v1ExpirePreAuthKeyRequest)
from hsapi_client.nodes import v1BackfillNodeIPsResponse
log = logging.getLogger() log = logging.getLogger()
@@ -104,3 +105,10 @@ def expirePKA(userName: str, key: str):
PreAuthKey().expire(req) PreAuthKey().expire(req)
return redirect(url_for('main.user', userName=userName)) return redirect(url_for('main.user', userName=userName))
@rest_blueprint.route('/backfillips', methods=['POST'])
@auth.authorize_admins('default')
def backfillips():
response = Node().backfillips()
return jsonify(response.changes)

6
poetry.lock generated
View File

@@ -452,13 +452,13 @@ files = [
[[package]] [[package]]
name = "hsapi-client" name = "hsapi-client"
version = "0.9.6" version = "0.9.7"
description = "Headscale API client" description = "Headscale API client"
optional = false optional = false
python-versions = "<4.0,>=3.11" python-versions = "<4.0,>=3.11"
files = [ files = [
{file = "hsapi_client-0.9.6-py3-none-any.whl", hash = "sha256:441cd219a2384f66511b8cca21224171b4e6753d16d364d984eb9887aa686a6c"}, {file = "hsapi_client-0.9.7-py3-none-any.whl", hash = "sha256:6cd8ac2a787112a02d7d5d3e029ceba0749844806b20b3c27247393cccd53def"},
{file = "hsapi_client-0.9.6.tar.gz", hash = "sha256:b6a4183fb9cdf95b0e864eec5b79ea18843e25379f928c4770b68e4f1ce8334b"}, {file = "hsapi_client-0.9.7.tar.gz", hash = "sha256:7a6bf7cb533a4f0431c322bc292f09559eb27b37177ea2101a6ea559dc0c9e47"},
] ]
[package.dependencies] [package.dependencies]

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "hsman" name = "hsman"
version = "0.9.15" version = "0.9.17"
description = "Flask Admin webui for Headscale" description = "Flask Admin webui for Headscale"
authors = ["Andrea Mistrali <andrea@mistrali.pw>"] authors = ["Andrea Mistrali <andrea@mistrali.pw>"]
license = "BSD" license = "BSD"