228 lines
8.6 KiB
HTML
228 lines
8.6 KiB
HTML
{% extends "base_settings_page.html" %}
|
|
{% block content %}
|
|
|
|
<form method="post" action="/admin/users" id="edit_user_form">
|
|
<!-- User ID -->
|
|
<div class="form-group">
|
|
<label class="form-label mt-4" for="userID">User ID</label>
|
|
<input class="form-control" id="userID" type="text" readonly=""
|
|
name="uid" value="{{ u.uid.0 }}"/>
|
|
</div>
|
|
|
|
<!-- User name -->
|
|
<div class="form-group">
|
|
<label class="form-label mt-4" for="username">Username</label>
|
|
<input class="form-control" id="username" type="text" autocomplete="nope"
|
|
name="username" value="{{ u.username }}" required/>
|
|
<div class="valid-feedback">This username is valid</div>
|
|
<div class="invalid-feedback">This username is already taken.</div>
|
|
</div>
|
|
|
|
<!-- First name -->
|
|
<div class="form-group">
|
|
<label class="form-label mt-4" for="first_name">First name</label>
|
|
<input class="form-control" id="first_name" type="text"
|
|
name="first_name" value="{{ u.first_name }}"/>
|
|
</div>
|
|
|
|
<!-- Last name -->
|
|
<div class="form-group">
|
|
<label class="form-label mt-4" for="last_name">Last name</label>
|
|
<input class="form-control" id="last_name" type="text"
|
|
name="last_name" value="{{ u.last_name }}"/>
|
|
</div>
|
|
|
|
<!-- Email -->
|
|
<div class="form-group">
|
|
<label class="form-label mt-4" for="email">Email address</label>
|
|
<input class="form-control" id="email" type="email"
|
|
name="email" value="{{ u.email }}"/>
|
|
</div>
|
|
|
|
<div class="form-group mt-4">
|
|
<!-- Generate new password -->
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="gen_new_password" id="gen_new_password" {% if
|
|
u.password.is_empty() %} checked="" {% endif %}>
|
|
<label class="form-check-label" for="gen_new_password">
|
|
Generate a new temporary password
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Enabled -->
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="enabled" id="enabled"
|
|
{% if u.enabled %} checked="" {% endif %}>
|
|
<label class="form-check-label" for="enabled">
|
|
Enabled
|
|
</label>
|
|
</div>
|
|
|
|
<!-- 2FA exemption after successful login -->
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="two_factor_exemption_after_successful_login"
|
|
id="two_factor_exemption_after_successful_login"
|
|
{% if u.two_factor_exemption_after_successful_login %} checked="" {% endif %}>
|
|
<label class="form-check-label" for="two_factor_exemption_after_successful_login">
|
|
Exempt user from 2FA authentication for an IP address after a successful login for a limited time
|
|
</label>
|
|
</div>
|
|
|
|
<!-- Admin -->
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="admin" id="admin"
|
|
{% if u.admin %} checked="" {% endif %}>
|
|
<label class="form-check-label" for="admin">
|
|
Grant admin privileges
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Two-Factor authentication -->
|
|
<input type="hidden" name="two_factor" value=""/>
|
|
{% if u.has_two_factor() %}
|
|
<fieldset class="form-group">
|
|
<legend class="mt-4">Two factor authentication</legend>
|
|
<strong>If you uncheck a factor, it will be DELETED</strong>
|
|
{% for f in u.two_factor %}
|
|
<div class="form-check">
|
|
<label class="form-check-label">
|
|
<input type="checkbox" class="form-check-input two-fact-checkbox"
|
|
value="{{ f.id.0 }}"
|
|
checked=""/>
|
|
{{ f.name }} (<img src="{{ f.type_image() }}" alt="Factor icon" style="height:1em;"/>
|
|
{{ f.type_str() }})
|
|
</label>
|
|
</div>
|
|
{% endfor %}
|
|
</fieldset>
|
|
{% endif %}
|
|
|
|
<!-- Two factor authentication history -->
|
|
{% if !u.last_successful_2fa.is_empty() %}
|
|
<fieldset class="form-group">
|
|
<legend class="mt-4">Last successful 2FA authentications</legend>
|
|
|
|
<!-- Clear 2FA history -->
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="clear_2fa_history" id="clear_2fa_history">
|
|
<label class="form-check-label" for="clear_2fa_history">
|
|
Clear 2FA authentication history
|
|
</label>
|
|
</div>
|
|
|
|
<ul>
|
|
{% for e in u.get_formatted_2fa_successful_logins() %}
|
|
{% if e.can_bypass_2fa %}<li style="font-weight: bold;">{{ e.ip }} - {{ e.fmt_time() }} - BYPASS 2FA</li>
|
|
{% else %}<li>{{ e.ip }} - {{ e.fmt_time() }}</li>{% endif %}
|
|
{% endfor %}
|
|
</ul>
|
|
</fieldset>
|
|
{% endif %}
|
|
|
|
<!-- Granted clients -->
|
|
<fieldset class="form-group">
|
|
<legend class="mt-4">Granted clients</legend>
|
|
<div class="form-check">
|
|
<label class="form-check-label">
|
|
<input type="radio" class="form-check-input" name="grant_type"
|
|
value="all_clients" {% if u.authorized_clients== None %} checked="" {% endif %}>
|
|
Grant all clients
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<label class="form-check-label">
|
|
<input type="radio" class="form-check-input" name="grant_type"
|
|
value="custom_clients" {% if u.authorized_clients !=None %} checked="checked" {% endif %}>
|
|
Manually specify allowed clients
|
|
</label>
|
|
</div>
|
|
|
|
<div id="clients_target">
|
|
<input type="hidden" name="granted_clients" value=""/>
|
|
{% for c in clients %}
|
|
<div class="form-check">
|
|
<input id="client-{{ c.id.0 }}" class="form-check-input authorize_client_checkbox" type="checkbox"
|
|
data-id="{{ c.id.0 }}"
|
|
{% if u.can_access_app(c.id) %} checked="" {% endif %}>
|
|
<label class="form-check-label" for="client-{{ c.id.0 }}">
|
|
{{ c.name }}
|
|
</label>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</fieldset>
|
|
|
|
<input type="submit" class="btn btn-primary mt-4" value="{{ _p.page_title }}">
|
|
</form>
|
|
|
|
<script>
|
|
// Check Username
|
|
async function find_username(username) {
|
|
let data = new URLSearchParams();
|
|
data.append("username", username);
|
|
|
|
return (await(await fetch("/admin/api/find_username", {
|
|
body: data,
|
|
method: "POST",
|
|
})).json()).user_id
|
|
}
|
|
|
|
const usernameEl = document.getElementById("username")
|
|
async function check_username() {
|
|
try {
|
|
usernameEl.classList.remove("is-invalid");
|
|
usernameEl.classList.remove("is-valid");
|
|
|
|
if (usernameEl.value === "")
|
|
return;
|
|
|
|
const userID = await find_username(usernameEl.value);
|
|
usernameEl.classList.add((userID === null || userID === "{{ u.uid.0 }}") ? "is-valid" : "is-invalid");
|
|
|
|
} catch(e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
check_username();
|
|
usernameEl.addEventListener("change", check_username);
|
|
usernameEl.addEventListener("keyup", check_username);
|
|
|
|
|
|
// Clients granted
|
|
function refreshDisplayAuthorizedClients() {
|
|
const clientsSelectorEl = document.getElementById("clients_target");
|
|
const radioBtn = document.querySelector("input[name=grant_type][value=custom_clients]");
|
|
clientsSelectorEl.style.display = radioBtn.checked ? "block" : "none";
|
|
}
|
|
refreshDisplayAuthorizedClients();
|
|
document.querySelectorAll("input[name=grant_type]").forEach(el=> {
|
|
el.addEventListener("change", refreshDisplayAuthorizedClients)
|
|
})
|
|
|
|
|
|
// Handle submitted form
|
|
const form = document.getElementById("edit_user_form");
|
|
form.addEventListener("submit", (ev) => {
|
|
ev.preventDefault();
|
|
|
|
const authorized_clients = [...document.querySelectorAll(".authorize_client_checkbox")]
|
|
.filter(e => e.checked)
|
|
.map(e => e.getAttribute("data-id")).join(",")
|
|
|
|
document.querySelector("input[name=granted_clients]").value = authorized_clients;
|
|
|
|
const factors_to_keep = [...document.querySelectorAll(".two-fact-checkbox")]
|
|
.filter(e => e.checked)
|
|
.map(e => e.value)
|
|
.join(";")
|
|
|
|
document.querySelector("input[name=two_factor]").value = factors_to_keep;
|
|
|
|
form.submit();
|
|
});
|
|
|
|
</script>
|
|
|
|
{% endblock content %} |