Files
headscale-webui/static/js/custom.js

1212 lines
50 KiB
JavaScript
Raw Normal View History

2023-03-21 19:03:06 +09:00
//-----------------------------------------------------------
// Search on Users and Machines pages
2023-03-21 19:03:06 +09:00
//-----------------------------------------------------------
2023-03-22 10:31:10 +09:00
function show_search() {
$('#nav-search').removeClass('hidden');
$('#nav-search').addClass('show');
$('#nav-content').removeClass('show');
$('#nav-content').addClass('hidden');
}
2023-03-21 20:23:53 +09:00
2023-03-22 10:31:10 +09:00
function hide_search() {
$('#nav-content').removeClass('hidden');
$('#nav-content').addClass('show');
$('#nav-search').removeClass('show');
$('#nav-search').addClass('hidden');
2023-03-22 12:42:16 +09:00
// Also remove the contents of the searchbox:
document.getElementById("search").value = ""
2023-03-22 12:48:49 +09:00
let cards = document.querySelectorAll('.searchable');
for (var i = 0; i < cards.length; i++) {
cards[i].classList.remove("hide");
}
2023-03-22 10:31:10 +09:00
}
function liveSearch() {
let cards = document.querySelectorAll('.searchable');
2023-03-22 11:36:27 +09:00
let search_query = document.getElementById("search").value;
2023-04-21 01:28:56 +08:00
2023-03-22 10:31:10 +09:00
for (var i = 0; i < cards.length; i++) {
2023-04-21 01:28:56 +08:00
if (cards[i].textContent.toLowerCase().includes(search_query.toLowerCase())) {
2023-03-22 10:31:10 +09:00
cards[i].classList.remove("hide");
} else {
cards[i].classList.add("hide");
}
}
2023-03-22 10:31:10 +09:00
}
2023-02-06 04:58:09 +00:00
//-----------------------------------------------------------
// General Helpers
//-----------------------------------------------------------
2023-04-21 01:28:56 +08:00
function loading() {
2023-02-06 04:58:09 +00:00
return `<center>
<div class="preloader-wrapper big active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle">
</div>
</div>
<div class="gap-patch">
<div class="circle">
</div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</center> `
}
function get_color(id) {
// Define the colors... Seems like a good number to start with
var colors = [
"red lighten-1",
"teal lighten-1",
"blue lighten-1",
"blue-grey lighten-1",
"indigo lighten-2",
"green lighten-1",
"deep-orange lighten-1",
"yellow lighten-2",
"purple lighten-2",
"indigo lighten-2",
"brown lighten-1",
"grey lighten-1"
];
index = id % colors.length
return colors[index]
}
// Generic modal used for alerts / problems
function load_modal_generic(type, title, message) {
console.log("Loading the generic modal")
2023-04-21 01:28:56 +08:00
element = document.getElementById('generic_modal')
2023-02-06 04:58:09 +00:00
content_element = document.getElementById('generic_modal_content')
2023-04-21 01:28:56 +08:00
title_element = document.getElementById('generic_modal_title')
2023-02-06 04:58:09 +00:00
content_element.innerHTML = loading()
title_element.innerHTML = "Loading..."
html = ""
switch (type) {
case "warning" || "Warning":
title_html = "Warning"
2023-04-21 01:28:56 +08:00
content_html = `
2023-02-06 04:58:09 +00:00
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle yellow">priority_high</i>
<span class="title">${title}</span>
<p>${message}</p>
</li>
</ul>`
break;
case "success" || "Success":
title_html = "Success"
2023-04-21 01:28:56 +08:00
content_html = `
2023-02-06 04:58:09 +00:00
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle green">check</i>
<span class="title">${title}</span>
<p>${message}</p>
</li>
</ul>`
break;
2023-04-21 01:28:56 +08:00
case "error" || "Error":
2023-02-06 04:58:09 +00:00
title_html = "Error"
2023-04-21 01:28:56 +08:00
content_html = `
2023-02-06 04:58:09 +00:00
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">${title}</span>
<p>${message}</p>
</li>
</ul>`
break;
case "information" || "Information":
title_html = "Information"
2023-04-21 01:28:56 +08:00
content_html = `
2023-02-06 04:58:09 +00:00
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle grey">help</i>
<span class="title">${title}</span>
<p>${message}</p>
</li>
</ul>`
break;
}
title_element.innerHTML = title_html
content_element.innerHTML = content_html
var instance = M.Modal.getInstance(element);
instance.open()
}
2023-03-17 18:19:28 +09:00
// https://stackoverflow.com/questions/3043775/how-to-escape-html#22706073
2023-04-21 01:28:56 +08:00
function escapeHTML(str) {
2023-03-17 18:19:28 +09:00
var p = document.createElement("p");
p.appendChild(document.createTextNode(str));
return p.innerHTML;
}
2023-02-06 04:58:09 +00:00
// Enables the Floating Action Button (FAB) for the Machines and Users page
2023-04-21 01:28:56 +08:00
document.addEventListener('DOMContentLoaded', function () {
2023-02-06 04:58:09 +00:00
var elems = document.querySelectorAll('.fixed-action-btn');
2023-04-21 01:28:56 +08:00
var instances = M.FloatingActionButton.init(elems, { hoverEnabled: false });
2023-02-06 04:58:09 +00:00
});
// Init the date picker when adding PreAuth keys
2023-04-21 01:28:56 +08:00
document.addEventListener('DOMContentLoaded', function () {
2023-02-06 04:58:09 +00:00
var elems = document.querySelectorAll('.datepicker');
var instances = M.Datepicker.init(elems);
});
//-----------------------------------------------------------
// Settings Page Actions
//-----------------------------------------------------------
function test_key() {
document.getElementById('test_modal_results').innerHTML = loading()
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var api_key = document.getElementById('api_key').value;
2023-02-06 04:58:09 +00:00
var data = $.ajax({
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/test_key",
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
data: JSON.stringify({ "api_key": api_key }),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
document.getElementById('test_modal_results').innerHTML = `
2023-02-06 04:58:09 +00:00
<ul class="collection">
<li class="collection-item avatar">
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
<i class="material-icons circle green">check</i>
<span class="title">Success</span>
<p>Key authenticated with the Headscale server.</p>
2023-02-06 04:58:09 +00:00
</li>
</ul>
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
<h6>Key Information</h6>
<table class="highlight">
<tbody>
<tr>
<td><b>Key ID</b></td>
<td>${response.id}</td>
</tr>
<tr>
<td><b>Prefix</b></td>
<td>${response.prefix}</td>
</tr>
<tr>
<td><b>Expiration Date</b></td>
<td>${response.expiration}</td>
</tr>
<tr>
<td><b>Creation Date</b></td>
<td>${response.createdAt}</td>
</tr>
</tbody>
</table>
2023-02-06 04:58:09 +00:00
`
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
},
error: function (xhr, textStatus, errorThrown) {
document.getElementById('test_modal_results').innerHTML = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">Error</span>
<p>Key authentication failed. Check your key.</p>
</li>
</ul>
`
2023-02-06 04:58:09 +00:00
}
})
}
function save_key() {
var api_key = document.getElementById('api_key').value;
if (!api_key) {
html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">Error</span>
<p>You must enter an API key before saving.</p>
</li>
</ul>
`
document.getElementById('test_modal_results').innerHTML = html
return
};
2023-04-21 01:28:56 +08:00
var data = { "api_key": api_key };
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/save_key",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
M.toast({ html: 'Testing key and saving...' });
test_key();
},
error: function (xhr, textStatus, errorThrown) {
M.toast({ html: xhr.responseText })
2023-02-06 04:58:09 +00:00
test_key();
}
})
}
//-----------------------------------------------------------
// Modal Loaders
//-----------------------------------------------------------
function load_modal_rename_user(user_id, old_name) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "green btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Rename"
2023-04-21 01:28:56 +08:00
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Rename user '" + old_name + "'?"
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle">language</i>
<span class="title">Information</span>
<p>You are about to rename the user '${old_name}'</p>
</li>
</ul>
<h6>New Name</h6>
<div class="input-field">
<i class="material-icons prefix">language</i>
<input value='${old_name}' id="new_user_name_form" type="text" data-length="32">
</div>
`
modal_body.innerHTML = body_html
2023-04-21 01:28:56 +08:00
$(document).ready(function () { $('input#new_user_name_form').characterCounter(); });
2023-02-06 04:58:09 +00:00
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'rename_user(' + user_id + ', "' + old_name + '")')
2023-02-06 04:58:09 +00:00
}
function load_modal_delete_user(user_id, user_name) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "red btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Delete"
2023-04-21 01:28:56 +08:00
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Delete user '" + user_name + "'?"
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">Warning</span>
<p>Are you sure you want to delete the user '${user_name}'?</p>
</li>
</ul>
`
modal_body.innerHTML = body_html
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'delete_user("' + user_id + '", "' + user_name + '")')
2023-02-06 04:58:09 +00:00
}
function load_modal_add_preauth_key(user_name) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "green btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Add"
2023-04-21 01:28:56 +08:00
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Adding a PreAuth key to '" + user_name + "'"
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle">help</i>
<span class="title">Information</span>
<p>
<ul>
<li>Pre-Auth keys can be used to authenticate to Headscale without manually registering a machine. Use the flag <code>--auth-key</code> to do so.</li>
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
<li>"Ephemeral" keys can be used to register devices that frequently come on and drop off the network (for example, docker containers)</li>
<li>Keys that are "Reusable" can be used multiple times. Keys that are "One Time Use" will expire after their first use.</li>
2023-02-06 04:58:09 +00:00
</ul>
</p>
</li>
</ul>
<h4>PreAuth Key Information</h4>
<br>
2023-02-28 21:36:02 +09:00
<input type="text" class="datepicker" id="preauth_key_expiration_date">
2023-02-06 04:58:09 +00:00
<p>
<label>
<input type="checkbox" class="filled-in" id="checkbox-reusable"/>
<span>Reusable</span>
</label>
</p>
<p>
<label>
<input type="checkbox" class="filled-in" id="checkbox-ephemeral" />
<span>Ephemeral</span>
</label>
</p>
`
modal_body.innerHTML = body_html
// Init the date picker
2023-04-21 01:28:56 +08:00
M.Datepicker.init(document.querySelector('.datepicker'), { format: 'yyyy-mm-dd' });
2023-02-06 04:58:09 +00:00
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'add_preauth_key("' + user_name + '")')
2023-02-06 04:58:09 +00:00
}
function load_modal_expire_preauth_key(user_name, key) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "red lighten-2 btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Expire"
2023-04-21 01:28:56 +08:00
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
modal_title.innerHTML = "Expire PreAuth Key?"
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">Warning</span>
<p>Are you sure you want to expire this key? It will become unusable afterwards, and any machine currently using it will disconnect.</p>
</li>
</ul>
`
modal_body.innerHTML = body_html
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'expire_preauth_key("' + user_name + '", "' + key + '")')
2023-02-06 04:58:09 +00:00
}
function load_modal_move_machine(machine_id) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "green btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Move"
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/machine_information",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (headscale) {
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/get_users",
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
data: "{}",
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Move machine '" + headscale.machine.givenName + "'?"
2023-02-06 04:58:09 +00:00
select_html = `<h6>Select a User</h6><select id='move-select'>`
2023-04-21 01:28:56 +08:00
for (let i = 0; i < response.users.length; i++) {
2023-02-06 04:58:09 +00:00
var name = response["users"][i]["name"]
2023-04-21 01:28:56 +08:00
select_html = select_html + `<option value="${name}">${name}</option>`
2023-02-06 04:58:09 +00:00
}
2023-04-21 01:28:56 +08:00
select_html = select_html + `</select>`
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle">language</i>
<span class="title">Information</span>
<p>You are about to move ${headscale.machine.givenName} to a new user.</p>
</li>
</ul>`
2023-04-21 01:28:56 +08:00
body_html = body_html + select_html
body_html = body_html + `<h6>Machine Information</h6>
2023-02-06 04:58:09 +00:00
<table class="highlight">
<tbody>
<tr>
<td><b>Machine ID</b></td>
<td>${headscale.machine.id}</td>
</tr>
<tr>
<td><b>Hostname</b></td>
<td>${headscale.machine.name}</td>
</tr>
<tr>
<td><b>User</b></td>
<td>${headscale.machine.user.name}</td>
</tr>
</tbody>
</table>
`
modal_body.innerHTML = body_html
M.FormSelect.init(document.querySelectorAll('select'))
}
})
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'move_machine(' + machine_id + ')')
2023-02-06 04:58:09 +00:00
}
})
}
function load_modal_delete_machine(machine_id) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "red btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Delete"
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/machine_information",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Delete machine '" + response.machine.givenName + "'?"
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle red">warning</i>
<span class="title">Warning</span>
<p>Are you sure you want to delete ${response.machine.givenName}?</p>
</li>
</ul>
<h6>Machine Information</h6>
<table class="highlight">
<tbody>
<tr>
<td><b>Machine ID</b></td>
<td>${response.machine.id}</td>
</tr>
<tr>
<td><b>Hostname</b></td>
<td>${response.machine.name}</td>
</tr>
<tr>
<td><b>User</b></td>
<td>${response.machine.user.name}</td>
</tr>
</tbody>
</table>
`
modal_body.innerHTML = body_html
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'delete_machine(' + machine_id + ')')
2023-02-06 04:58:09 +00:00
}
})
}
function load_modal_rename_machine(machine_id) {
document.getElementById('modal_content').innerHTML = loading()
document.getElementById('modal_title').innerHTML = "Loading..."
document.getElementById('modal_confirm').className = "green btn-flat white-text"
document.getElementById('modal_confirm').innerText = "Rename"
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/machine_information",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
modal = document.getElementById('card_modal');
modal_title = document.getElementById('modal_title');
modal_body = document.getElementById('modal_content');
2023-02-06 04:58:09 +00:00
modal_confirm = document.getElementById('modal_confirm');
2023-04-21 01:28:56 +08:00
modal_title.innerHTML = "Rename machine '" + response.machine.givenName + "'?"
2023-02-06 04:58:09 +00:00
body_html = `
<ul class="collection">
<li class="collection-item avatar">
<i class="material-icons circle">devices</i>
<span class="title">Information</span>
<p>You are about to rename ${response.machine.givenName}</p>
</li>
</ul>
<h6>New Name</h6>
<div class="input-field">
<input value='${response.machine.givenName}' id="new_name_form" type="text">
<label for="new_name_form" class="active">New Machine Name</label>
</div>
<h6>Machine Information</h6>
<table class="highlight">
<tbody>
<tr>
<td><b>Machine ID</b></td>
<td>${response.machine.id}</td>
</tr>
<tr>
<td><b>Hostname</b></td>
<td>${response.machine.name}</td>
</tr>
<tr>
<td><b>User</b></td>
<td>${response.machine.user.name}</td>
</tr>
</tbody>
</table>
`
modal_body.innerHTML = body_html
2023-04-21 01:28:56 +08:00
modal_confirm.setAttribute('onclick', 'rename_machine(' + machine_id + ')')
2023-02-06 04:58:09 +00:00
}
})
}
function load_modal_add_machine() {
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/get_users",
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
data: "{}",
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-02-06 04:58:09 +00:00
modal_body = document.getElementById('default_add_new_machine_modal');
modal_confirm = document.getElementById('new_machine_modal_confirm');
select_html = `
<div class="col s12 m6">
<div class="input-field">
<i class="material-icons prefix">language</i>
<select id='add_machine_user_select'>
<option value="" disabled selected>Select a User</option>`
2023-04-21 01:28:56 +08:00
for (let i = 0; i < response.users.length; i++) {
2023-02-06 04:58:09 +00:00
var name = response["users"][i]["name"]
2023-04-21 01:28:56 +08:00
select_html = select_html + `<option value="${name}">${name}</option>`
2023-02-06 04:58:09 +00:00
}
select_html = select_html + `
<label>Select a User</label>
</select>
</div>
</div>`
select_html = select_html + `
<div class="col s12 m6">
<div class="input-field">
<i class="material-icons prefix">vpn_key</i>
<input id="add_machine_key_field" type="password">
<label for="add_machine_key_field">Machine Registration Key</label>
</div>
</div>`
2023-04-21 01:28:56 +08:00
for (let i = 0; i < response.users.length; i++) {
2023-02-06 04:58:09 +00:00
var name = response["users"][i]["name"]
}
modal_body.innerHTML = select_html
// Initialize the form and the machine tabs
2023-04-21 01:28:56 +08:00
M.FormSelect.init(document.querySelectorAll('select'), { classes: 'add_machine_selector_class' })
2023-02-06 04:58:09 +00:00
M.Tabs.init(document.getElementById('new_machine_tabs'));
}
})
}
//-----------------------------------------------------------
// Machine Page Actions
//-----------------------------------------------------------
function delete_chip(machine_id, chipsData) {
// We need to get ALL the current tags -- We don't care about what's deleted, just what's remaining
// chipsData is an array generated from from the creation of the array.
chips = JSON.stringify(chipsData)
var formattedData = [];
for (let tag in chipsData) {
2023-04-21 01:28:56 +08:00
formattedData[tag] = '"tag:' + chipsData[tag].tag + '"'
2023-02-06 04:58:09 +00:00
}
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id, "tags": formattedData }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/set_machine_tags",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
M.toast({ html: 'Tag removed.' });
2023-02-06 04:58:09 +00:00
}
})
}
function add_chip(machine_id, chipsData) {
chips = JSON.stringify(chipsData).toLowerCase()
chipsData[chipsData.length - 1].tag = chipsData[chipsData.length - 1].tag.trim().replace(/\s+/g, '-')
last_chip_fixed = chipsData[chipsData.length - 1].tag
var formattedData = [];
for (let tag in chipsData) {
2023-04-21 01:28:56 +08:00
formattedData[tag] = '"tag:' + chipsData[tag].tag + '"'
2023-02-06 04:58:09 +00:00
}
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id, "tags": formattedData }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/set_machine_tags",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
M.toast({ html: 'Tag "' + last_chip_fixed + '" added.' });
2023-02-06 04:58:09 +00:00
}
})
}
function add_machine() {
2023-04-21 01:28:56 +08:00
var key = document.getElementById('add_machine_key_field').value
2023-02-06 04:58:09 +00:00
var user = document.getElementById('add_machine_user_select').value
2023-04-21 01:28:56 +08:00
var data = { "key": key, "user": user }
2023-02-06 04:58:09 +00:00
if (user == "") {
load_modal_generic("error", "User is empty", "Select a user before submitting")
return
}
if (key == "") {
load_modal_generic("error", "Key is empty", "Input the key generated by your <code>tailscale login</code> command")
return
}
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/register_machine",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
window.location.reload()
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error adding machine", JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function rename_machine(machine_id) {
var new_name = document.getElementById('new_name_form').value;
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id, "new_name": new_name };
2023-02-06 04:58:09 +00:00
// String to test against
2023-04-21 01:28:56 +08:00
var regexIT = /[`!@#$%^&*()_+\=\[\]{};':"\\|,.<>\/?~]/;
if (regexIT.test(new_name)) { load_modal_generic("error", "Invalid Name", "Name cannot contain special characters ('" + regexIT + "')"); return }
2023-02-06 04:58:09 +00:00
// If there are characters other than - and alphanumeric, throw an error
2023-04-21 01:28:56 +08:00
if (new_name.includes(' ')) { load_modal_generic("error", "Name cannot have spaces", "Allowed characters are dashes (-) and alphanumeric characters"); return }
2023-02-06 04:58:09 +00:00
// If it is longer than 32 characters, throw an error
if (new_name.length > 32) { load_modal_generic("error", "Name is too long", "The name name is too long. Maximum length is 32 characters"); return }
// If the new_name is empty, throw an error
2023-04-21 01:28:56 +08:00
if (!new_name) { load_modal_generic("error", "Name can't be empty", "Please enter a machine name before submitting."); return }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/rename_machine",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
2023-02-06 04:58:09 +00:00
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
document.getElementById(machine_id + '-name-container').innerHTML = machine_id + ". " + escapeHTML(new_name)
M.toast({ html: 'Machine ' + machine_id + ' renamed to ' + escapeHTML(new_name) });
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error setting the machine name", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function move_machine(machine_id) {
new_user = document.getElementById('move-select').value
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id, "user": new_user };
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/move_user",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-02-06 04:58:09 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
2023-04-21 01:28:56 +08:00
document.getElementById(machine_id + '-user-container').innerHTML = response.machine.user.name
document.getElementById(machine_id + '-ns-badge').innerHTML = response.machine.user.name
2023-02-06 04:58:09 +00:00
// Get the color and set it
var user_color = get_color(response.machine.user.id)
2023-04-21 01:28:56 +08:00
document.getElementById(machine_id + '-ns-badge').className = "badge ipinfo " + user_color + " white-text hide-on-small-only"
2023-02-06 04:58:09 +00:00
2023-04-21 01:28:56 +08:00
M.toast({ html: "'" + response.machine.givenName + "' moved to user " + response.machine.user.name });
2023-02-06 04:58:09 +00:00
}
})
}
function delete_machine(machine_id) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "machine_id": machine_id };
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/delete_machine",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-02-06 04:58:09 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
// When the machine is deleted, hide its collapsible:
2023-04-21 01:28:56 +08:00
document.getElementById(machine_id + '-main-collapsible').className = "collapsible popout hide";
2023-02-06 04:58:09 +00:00
2023-04-21 01:28:56 +08:00
M.toast({ html: 'Machine deleted.' });
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error deleting machine", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
2023-03-24 14:12:21 +09:00
function toggle_exit(route1, route2, exit_id, current_state, page) {
2023-04-21 01:28:56 +08:00
var data1 = { "route_id": route1, "current_state": current_state }
var data2 = { "route_id": route2, "current_state": current_state }
2023-03-24 14:12:21 +09:00
var element = document.getElementById(exit_id);
var disabledClass = ""
2023-04-21 01:28:56 +08:00
var enabledClass = ""
2023-03-24 14:12:21 +09:00
if (page == "machines") {
disabledClass = "waves-effect waves-light btn-small red lighten-2 tooltipped";
2023-04-21 01:28:56 +08:00
enabledClass = "waves-effect waves-light btn-small green lighten-2 tooltipped";
2023-03-24 14:12:21 +09:00
}
if (page == "routes") {
disabledClass = "material-icons red-text text-lighten-2 tooltipped";
2023-04-21 01:28:56 +08:00
enabledClass = "material-icons green-text text-lighten-2 tooltipped";
2023-03-24 14:12:21 +09:00
}
var disabledTooltip = "Click to enable"
2023-04-21 01:28:56 +08:00
var enabledTooltip = "Click to disable"
var disableState = "False"
var enableState = "True"
var action_taken = "unchanged.";
2023-03-24 14:12:21 +09:00
2023-03-22 14:31:30 +09:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-22 14:31:30 +09:00
url: "api/update_route",
data: JSON.stringify(data1),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-03-22 14:31:30 +09:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-22 14:31:30 +09:00
url: "api/update_route",
data: JSON.stringify(data2),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-03-22 14:31:30 +09:00
// Response is a JSON object containing the Headscale API response of /v1/api/machines/<id>/route
if (element.className == disabledClass) {
2023-04-21 01:28:56 +08:00
element.className = enabledClass
action_taken = "enabled."
2023-03-22 14:31:30 +09:00
element.setAttribute('data-tooltip', enabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_exit(' + route1 + ', ' + route2 + ', "' + exit_id + '", "' + enableState + '", "' + page + '")')
2023-03-22 14:31:30 +09:00
} else if (element.className == enabledClass) {
2023-04-21 01:28:56 +08:00
element.className = disabledClass
action_taken = "disabled."
2023-03-22 14:31:30 +09:00
element.setAttribute('data-tooltip', disabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_exit(' + route1 + ', ' + route2 + ', "' + exit_id + '", "' + disableState + '", "' + page + '")')
2023-03-22 14:31:30 +09:00
}
2023-04-21 01:28:56 +08:00
M.toast({ html: 'Exit Route ' + action_taken });
2023-03-22 14:31:30 +09:00
}
})
}
})
2023-03-22 13:58:51 +09:00
}
2023-03-24 12:10:38 +09:00
function toggle_route(route_id, current_state, page) {
2023-04-21 01:28:56 +08:00
var data = { "route_id": route_id, "current_state": current_state }
2023-03-24 11:49:49 +09:00
var element = document.getElementById(route_id);
2023-03-24 12:53:11 +09:00
2023-03-24 12:18:04 +09:00
var disabledClass = ""
2023-04-21 01:28:56 +08:00
var enabledClass = ""
2023-03-24 12:18:04 +09:00
2023-03-24 12:24:15 +09:00
if (page == "machines") {
2023-03-24 13:02:32 +09:00
disabledClass = "waves-effect waves-light btn-small red lighten-2 tooltipped";
2023-04-21 01:28:56 +08:00
enabledClass = "waves-effect waves-light btn-small green lighten-2 tooltipped";
2023-03-24 13:02:32 +09:00
}
if (page == "routes") {
2023-03-24 12:53:11 +09:00
disabledClass = "material-icons red-text text-lighten-2 tooltipped";
2023-04-21 01:28:56 +08:00
enabledClass = "material-icons green-text text-lighten-2 tooltipped";
2023-03-24 11:48:12 +09:00
}
2023-03-24 12:53:11 +09:00
2023-03-24 11:48:12 +09:00
var disabledTooltip = "Click to enable"
2023-04-21 01:28:56 +08:00
var enabledTooltip = "Click to disable"
var disableState = "False"
var enableState = "True"
var action_taken = "unchanged.";
2023-03-24 08:16:44 +09:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-24 08:16:44 +09:00
url: "api/update_route",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-03-24 08:16:44 +09:00
if (element.className == disabledClass) {
2023-03-24 11:48:12 +09:00
element.className = enabledClass
2023-04-21 01:28:56 +08:00
action_taken = "enabled."
2023-03-24 08:16:44 +09:00
element.setAttribute('data-tooltip', enabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_route(' + route_id + ', "' + enableState + '", "' + page + '")')
2023-03-24 08:16:44 +09:00
} else if (element.className == enabledClass) {
2023-03-24 11:48:12 +09:00
element.className = disabledClass
2023-04-21 01:28:56 +08:00
action_taken = "disabled."
2023-03-24 08:16:44 +09:00
element.setAttribute('data-tooltip', disabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_route(' + route_id + ', "' + disableState + '", "' + page + '")')
2023-03-24 08:16:44 +09:00
}
2023-04-21 01:28:56 +08:00
M.toast({ html: 'Route ' + action_taken });
2023-03-24 08:16:44 +09:00
}
})
}
2023-03-24 11:48:12 +09:00
2023-03-29 13:59:34 +09:00
function get_routes() {
2023-03-30 10:01:49 +09:00
console.log("Getting info for all routes")
2023-03-30 11:38:53 +09:00
var data
2023-03-29 13:59:34 +09:00
$.ajax({
2023-03-30 11:26:10 +09:00
async: false,
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-29 13:59:34 +09:00
url: "api/get_routes",
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
data: "{}",
2023-03-29 13:59:34 +09:00
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-03-30 11:09:04 +09:00
console.log("Got all routes.")
2023-03-30 11:38:53 +09:00
data = response
2023-03-29 13:59:34 +09:00
}
})
2023-03-30 11:38:53 +09:00
return data
2023-03-29 13:59:34 +09:00
}
2023-03-30 09:47:27 +09:00
function toggle_failover_route_routespage(routeid, current_state, prefix, route_id_list) {
2023-03-29 13:59:34 +09:00
// First, toggle the route:
2023-03-29 17:58:52 +09:00
// toggle_route(route_id, current_state, page)
2023-04-21 01:28:56 +08:00
var data = { "route_id": routeid, "current_state": current_state }
console.log("Data: " + JSON.stringify(data))
console.log("Passed in: " + routeid + ", " + current_state + ", " + prefix + ", " + route_id_list)
2023-03-30 09:47:27 +09:00
var element = document.getElementById(routeid);
2023-03-29 17:58:52 +09:00
var disabledClass = "material-icons red-text text-lighten-2 tooltipped";
2023-04-21 01:28:56 +08:00
var enabledClass = "material-icons green-text text-lighten-2 tooltipped";
2023-03-30 13:01:59 +09:00
var failover_disabledClass = "material-icons small left red-text text-lighten-2"
2023-04-21 01:28:56 +08:00
var failover_enabledClass = "material-icons small left green-text text-lighten-2"
2023-03-29 17:58:52 +09:00
var disabledTooltip = "Click to enable"
2023-04-21 01:28:56 +08:00
var enabledTooltip = "Click to disable"
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var disableState = false
var enableState = true
2023-04-21 01:28:56 +08:00
var action_taken = "unchanged."
2023-03-30 10:00:20 +09:00
2023-03-29 17:58:52 +09:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-29 17:58:52 +09:00
url: "api/update_route",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
console.log("Success: Route ID: " + routeid)
console.log("Success: route_id_list: " + route_id_list)
2023-03-29 17:58:52 +09:00
if (element.className == disabledClass) {
element.className = enabledClass
2023-04-21 01:28:56 +08:00
action_taken = "enabled."
2023-03-29 17:58:52 +09:00
element.setAttribute('data-tooltip', enabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_failover_route_routespage(' + routeid + ', "' + enableState + '", "' + prefix + '", [' + route_id_list + '])')
2023-03-29 17:58:52 +09:00
} else if (element.className == enabledClass) {
element.className = disabledClass
2023-04-21 01:28:56 +08:00
action_taken = "disabled."
2023-03-29 17:58:52 +09:00
element.setAttribute('data-tooltip', disabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_failover_route_routespage(' + routeid + ', "' + disableState + '", "' + prefix + '", [' + route_id_list + '])')
2023-03-29 17:58:52 +09:00
}
2023-04-21 01:28:56 +08:00
M.toast({ html: 'Route ' + action_taken });
2023-03-29 17:58:52 +09:00
2023-03-30 10:38:40 +09:00
// Get all route info:
2023-04-21 01:28:56 +08:00
console.log("Getting info for prefix " + prefix)
2023-03-29 17:58:52 +09:00
var routes = get_routes()
2023-03-30 13:20:18 +09:00
var failover_enabled = false
2023-03-30 10:38:40 +09:00
// Get the primary and enabled displays for the prefix:
2023-04-21 01:28:56 +08:00
for (let i = 0; i < route_id_list.length; i++) {
console.log("route_id_list[" + i + "]: " + route_id_list[i])
2023-03-30 12:33:37 +09:00
var route_id = route_id_list[i]
2023-04-21 01:28:56 +08:00
var route_index = route_id - 1
console.log("Looking for route " + route_id + " at index " + route_index)
console.log("isPrimary: " + routes["routes"][route_index]["isPrimary"])
2023-03-30 12:33:37 +09:00
2023-03-30 10:38:40 +09:00
// Set the Primary class:
2023-04-21 01:28:56 +08:00
var primary_element = document.getElementById(route_id + "-primary")
var primary_status = routes["routes"][route_index]["isPrimary"]
var enabled_status = routes["routes"][route_index]["enabled"]
2023-03-30 12:33:37 +09:00
2023-04-21 01:28:56 +08:00
console.log("enabled_status: " + enabled_status)
2023-03-30 13:01:59 +09:00
2023-03-30 12:57:35 +09:00
if (enabled_status == true) {
2023-03-30 13:13:26 +09:00
failover_enabled = true
2023-03-30 12:57:35 +09:00
}
2023-04-21 01:28:56 +08:00
console.log("Setting primary class '" + route_id + "-primary': " + primary_status)
2023-03-30 12:03:55 +09:00
if (primary_status == true) {
2023-03-30 10:48:41 +09:00
console.log("Detected this route is primary. Setting the class")
2023-03-30 10:38:40 +09:00
primary_element.className = enabledClass
2023-03-30 12:03:55 +09:00
} else if (primary_status == false) {
2023-03-30 10:48:41 +09:00
console.log("Detected this route is NOT primary. Setting the class")
2023-03-30 10:38:40 +09:00
primary_element.className = disabledClass
}
2023-03-30 12:57:35 +09:00
}
// if any route is enabled, set the prefix enable icon to enabled:
var failover_element = document.getElementById(prefix)
2023-04-21 01:28:56 +08:00
console.log("Failover enabled: " + failover_enabled)
2023-03-30 12:57:35 +09:00
if (failover_enabled == true) {
2023-03-30 13:01:59 +09:00
failover_element.className = failover_enabledClass
2023-03-30 12:57:35 +09:00
}
else if (failover_enabled == false) {
2023-03-30 13:01:59 +09:00
failover_element.className = failover_disabledClass
2023-03-29 17:58:52 +09:00
}
}
})
}
2023-03-29 13:59:34 +09:00
2023-03-22 21:07:22 +09:00
function toggle_failover_route(route_id, current_state, color) {
2023-04-21 01:28:56 +08:00
var data = { "route_id": route_id, "current_state": current_state }
2023-03-22 21:07:22 +09:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-03-22 21:07:22 +09:00
url: "api/update_route",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
2023-03-22 21:07:22 +09:00
// Response is a JSON object containing the Headscale API response of /v1/api/machines/<id>/route
2023-04-21 01:28:56 +08:00
var element = document.getElementById(route_id);
var disabledClass = "waves-effect waves-light btn-small red lighten-2 tooltipped";
var enabledClass = "waves-effect waves-light btn-small " + color + " lighten-2 tooltipped";
2023-03-22 22:07:12 +09:00
var disabledTooltip = "Click to enable (Failover Pair)"
2023-04-21 01:28:56 +08:00
var enabledTooltip = "Click to disable (Failover Pair)"
var disableState = "False"
var enableState = "True"
var action_taken = "unchanged.";
2023-02-06 04:58:09 +00:00
if (element.className == disabledClass) {
// 1. Change the class to change the color of the icon
// 2. Change the "action taken" for the M.toast popup
// 3. Change the tooltip to say "Click to enable/disable"
2023-04-21 01:28:56 +08:00
element.className = enabledClass
var action_taken = "enabled."
2023-02-06 04:58:09 +00:00
element.setAttribute('data-tooltip', enabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_failover_route(' + route_id + ', "' + enableState + '", "' + color + '")')
2023-02-06 04:58:09 +00:00
} else if (element.className == enabledClass) {
2023-04-21 01:28:56 +08:00
element.className = disabledClass
var action_taken = "disabled."
2023-02-06 04:58:09 +00:00
element.setAttribute('data-tooltip', disabledTooltip)
2023-04-21 01:28:56 +08:00
element.setAttribute('onclick', 'toggle_failover_route(' + route_id + ', "' + disableState + '", "' + color + '")')
2023-02-06 04:58:09 +00:00
}
2023-04-21 01:28:56 +08:00
M.toast({ html: 'Route ' + action_taken });
2023-02-06 04:58:09 +00:00
}
})
}
//-----------------------------------------------------------
// Machine Page Helpers
//-----------------------------------------------------------
function btn_toggle(state) {
2023-04-21 01:28:56 +08:00
if (state == "show") { document.getElementById('new_machine_modal_confirm').className = 'green btn-flat white-text' }
else { document.getElementById('new_machine_modal_confirm').className = 'green btn-flat white-text hide' }
2023-02-06 04:58:09 +00:00
}
//-----------------------------------------------------------
// User Page Actions
//-----------------------------------------------------------
function rename_user(user_id, old_name) {
var new_name = document.getElementById('new_user_name_form').value;
2023-04-21 01:28:56 +08:00
var data = { "old_name": old_name, "new_name": new_name }
2023-02-06 04:58:09 +00:00
// String to test against
2023-04-21 01:28:56 +08:00
var regexIT = /[`!@#$%^&*()_+\=\[\]{};':"\\|,.<>\/?~]/;
if (regexIT.test(new_name)) { load_modal_generic("error", "Invalid Name", "Name cannot contain special characters ('" + regexIT + "')"); return }
2023-02-06 04:58:09 +00:00
// If there are characters other than - and alphanumeric, throw an error
2023-04-21 01:28:56 +08:00
if (new_name.includes(' ')) { load_modal_generic("error", "Name cannot have spaces", "Allowed characters are dashes (-) and alphanumeric characters"); return }
2023-02-06 04:58:09 +00:00
// If it is longer than 32 characters, throw an error
if (new_name.length > 32) { load_modal_generic("error", "Name is too long", "The user name is too long. Maximum length is 32 characters"); return }
// If the new_name is empty, throw an error
2023-04-21 01:28:56 +08:00
if (!new_name) { load_modal_generic("error", "Name can't be empty", "The user name cannot be empty."); return }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/rename_user",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
// Rename the user on the page:
document.getElementById(user_id + '-name-span').innerHTML = escapeHTML(new_name)
// Set the button to use the NEW name as the OLD name for both buttons
var rename_button_sm = document.getElementById(user_id + '-rename-user-sm')
rename_button_sm.setAttribute('onclick', 'load_modal_rename_user(' + user_id + ', "' + new_name + '")')
var rename_button_lg = document.getElementById(user_id + '-rename-user-lg')
rename_button_lg.setAttribute('onclick', 'load_modal_rename_user(' + user_id + ', "' + new_name + '")')
// Send the completion toast
M.toast({ html: "User '" + old_name + "' renamed to '" + new_name + "'." })
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error setting user name", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function delete_user(user_id, user_name) {
2023-04-21 01:28:56 +08:00
var data = { "name": user_name };
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/delete_user",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
// When the machine is deleted, hide its collapsible:
document.getElementById(user_id + '-main-collapsible').className = "collapsible popout hide";
M.toast({ html: 'User deleted.' });
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error deleting user", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function add_user() {
var user_name = document.getElementById('add_user_name_field').value
2023-04-21 01:28:56 +08:00
var data = { "name": user_name }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/add_user",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
// Send the completion toast
M.toast({ html: "User '" + user_name + "' added to Headscale. Refreshing..." })
window.location.reload()
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error adding user", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function add_preauth_key(user_name) {
2023-04-21 01:28:56 +08:00
var date = document.getElementById('preauth_key_expiration_date').value
var ephemeral = document.getElementById('checkbox-ephemeral').checked
var reusable = document.getElementById('checkbox-reusable').checked
var expiration = date + "T00:00:00.000Z" // Headscale format.
2023-02-06 04:58:09 +00:00
// If there is no date, error:
2023-04-21 01:28:56 +08:00
if (!date) { load_modal_generic("error", "Invalid Date", "Please enter a valid date"); return }
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
var data = { "user": user_name, "reusable": reusable, "ephemeral": ephemeral, "expiration": expiration, "acl_tags": [] }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/add_preauth_key",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Send the completion toast
M.toast({ html: 'PreAuth key created in user ' + user_name })
// If this is successful, we should reload the table and close the modal:
var user_data = { "user": user_name }
$.ajax({
type: "POST",
url: "api/build_preauthkey_table",
data: JSON.stringify(user_data),
contentType: "application/json",
success: function (table_data) {
table = document.getElementById(user_name + '-preauth-keys-collection')
table.innerHTML = table_data
// The tooltips need to be re-initialized afterwards:
M.Tooltip.init(document.querySelectorAll('.tooltipped'))
}
})
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
2023-02-06 04:58:09 +00:00
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// The tooltips need to be re-initialized afterwards:
M.Tooltip.init(document.querySelectorAll('.tooltipped'))
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error adding a pre-auth key", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
function expire_preauth_key(user_name, key) {
2023-04-21 01:28:56 +08:00
var data = { "user": user_name, "key": key }
2023-02-06 04:58:09 +00:00
$.ajax({
2023-04-21 01:28:56 +08:00
type: "POST",
2023-02-06 04:58:09 +00:00
url: "api/expire_preauth_key",
data: JSON.stringify(data),
contentType: "application/json",
2023-04-21 01:28:56 +08:00
success: function (response) {
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// Send the completion toast
M.toast({ html: 'PreAuth expired in ' + user_name })
// If this is successful, we should reload the table and close the modal:
var user_data = { "user": user_name }
$.ajax({
type: "POST",
url: "api/build_preauthkey_table",
data: JSON.stringify(user_data),
contentType: "application/json",
success: function (table_data) {
table = document.getElementById(user_name + '-preauth-keys-collection')
table.innerHTML = table_data
// The tooltips need to be re-initialized afterwards:
M.Tooltip.init(document.querySelectorAll('.tooltipped'))
}
})
// Get the modal element and close it
modal_element = document.getElementById('card_modal')
M.Modal.getInstance(modal_element).close()
2023-02-06 04:58:09 +00:00
Complete the major refactor Major part of #73 Unfortunately, it wasn't possible to split it to multiple smaller commits, since the changes touched the entire application substantially. Here is a short list of major changes: 1. Create a separate library (headscale-api), which is used as a convenient abstraction layer providing Pythonic interface with Pydantic. Headscale API is fully asynchronous library, benefitting from improved concurrency for backend requests thus increasing page load speed, e.g., on "Machines" page. 2. Create a common common, validated with flask-pydantic API passthrough layer from GUI to the backend. 3. Move authentication to a separate (auth.py), consolidating the functionality in a single place (with better place for expansion in the future). 4. Move configuration management to a separate module (config.py). Use Pydantic's BaseSettings for reading values from environment, with extensive validation and error reporting. 5. Reduce the number of health checks. - Now, most are performed during server initialization. If any test fails, the server is started in tainted mode, with only the error page exposed (thus reducing the surface of attack in invalid state). - Key checks are implicit in the requests to the backend and guarded by `@headscale.key_check_guard` decorator. - Key renewal is moved to server-side scheduler. 6. Introduce type hints to the level satisfactory for mypy static analysis. Also, enable some other linters in CI and add optional pre-commit hooks. 7. Properly handle some error states. Instead of returning success and handling different responses, if something fails, there is HTTP error code and standard response for it. 8. General formatting, small rewrites for clarity and more idiomatic Python constructs. Signed-off-by: Marek Pikuła <marek.pikula@embevity.com>
2023-04-21 05:26:11 +00:00
// The tooltips need to be re-initialized afterwards:
M.Tooltip.init(document.querySelectorAll('.tooltipped'))
},
error: function (xhr, textStatus, errorThrown) {
load_modal_generic("error", "Error expiring a pre-auth key", "Headscale response: " + JSON.parse(xhr.responseText).message)
2023-02-06 04:58:09 +00:00
}
})
}
//-----------------------------------------------------------
// User Page Helpers
//-----------------------------------------------------------
// Toggle expired items on the Users PreAuth section:
function toggle_expired() {
var toggle_hide = document.getElementsByClassName('expired-row');
2023-04-21 01:28:56 +08:00
var hidden = document.getElementsByClassName('expired-row hide');
2023-02-06 04:58:09 +00:00
if (hidden.length == 0) {
for (var i = 0; i < toggle_hide.length; i++) {
toggle_hide[i].className = "expired-row hide";
}
} else if (hidden.length > 0) {
for (var i = 0; i < toggle_hide.length; i++) {
toggle_hide[i].className = "expired-row";
}
}
}
// Copy a PreAuth Key to the clipboard. Show only the Prefix by default
function copy_preauth_key(key) {
navigator.clipboard.writeText(key);
2023-04-21 01:28:56 +08:00
M.toast({ html: 'PreAuth key copied to clipboard.' })
}