mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2024-12-04 10:24:42 +02:00
[BS5] fix merging bugs
This commit is contained in:
parent
ecc16c69e6
commit
45e97b3753
@ -271,6 +271,28 @@ code {
|
|||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-header {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataTables_info {
|
||||||
|
margin: 15px 0 !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
.dataTables_paginate, .dataTables_length, .dataTables_filter {
|
||||||
|
margin: 15px 0 !important;
|
||||||
|
}
|
||||||
|
.dtr-details {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.dtr-title {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
table.dataTable>tbody>tr.child ul.dtr-details>li {
|
||||||
|
border-bottom: 1px solid rgba(239, 239, 239, 0.129);
|
||||||
|
padding: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
.tag-box {
|
.tag-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@ -316,3 +338,59 @@ code {
|
|||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before:hover,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before:hover {
|
||||||
|
background-color: #5e5e5e;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.dtr-control:before,
|
||||||
|
table.dataTable td.dt-control:before {
|
||||||
|
background-color: #979797 !important;
|
||||||
|
border: 1.5px solid #616161 !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
color: #fff;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
line-height: 1.25em;
|
||||||
|
border-radius: 0px;
|
||||||
|
box-shadow: none;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: 0.5s all;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td.dtr-control:before,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th.dtr-control:before,
|
||||||
|
table.dataTable td.dt-control:before {
|
||||||
|
background-color: #979797 !important;
|
||||||
|
}
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,
|
||||||
|
table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty {
|
||||||
|
background-color: #fbfbfb;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped>tbody>tr>td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
table.dataTable.table-striped>tbody>tr>td>input[type="checkbox"] {
|
||||||
|
margin-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.btn-check-label {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caret {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
a[aria-expanded='true'] > .caret,
|
||||||
|
button[aria-expanded='true'] > .caret {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-details {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.list-group-header {
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
@ -48,7 +48,7 @@ legend {
|
|||||||
border-color: #7a7a7a !important;
|
border-color: #7a7a7a !important;
|
||||||
}
|
}
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background-color: #383838;
|
background-color: #414141;
|
||||||
}
|
}
|
||||||
.modal-header {
|
.modal-header {
|
||||||
border-bottom: 1px solid #161616;
|
border-bottom: 1px solid #161616;
|
||||||
|
@ -77,7 +77,6 @@ jQuery(function($){
|
|||||||
type: "GET",
|
type: "GET",
|
||||||
url: "/api/v1/get/domain-admin/all",
|
url: "/api/v1/get/domain-admin/all",
|
||||||
dataSrc: function(data){
|
dataSrc: function(data){
|
||||||
console.log(data);
|
|
||||||
return process_table_data(data, 'domainadminstable');
|
return process_table_data(data, 'domainadminstable');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -133,7 +132,6 @@ jQuery(function($){
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
initComplete: function(settings, json){
|
initComplete: function(settings, json){
|
||||||
console.log(settings);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,9 @@ $(document).ready(function() {
|
|||||||
// create host cpu and mem charts
|
// create host cpu and mem charts
|
||||||
createHostCpuAndMemChart();
|
createHostCpuAndMemChart();
|
||||||
// check for new version
|
// check for new version
|
||||||
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
if (mailcow_info.branch === "master"){
|
||||||
|
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
||||||
|
}
|
||||||
update_container_stats()
|
update_container_stats()
|
||||||
});
|
});
|
||||||
jQuery(function($){
|
jQuery(function($){
|
||||||
@ -1108,75 +1110,83 @@ function update_stats(timeout=5){
|
|||||||
}
|
}
|
||||||
// update specific container stats - every n (default 5s) seconds
|
// update specific container stats - every n (default 5s) seconds
|
||||||
function update_container_stats(timeout=5){
|
function update_container_stats(timeout=5){
|
||||||
for (let container in containersToUpdate){
|
|
||||||
container_id = containersToUpdate[container].id;
|
if ($('#tab-containers').hasClass('active')) {
|
||||||
if (containersToUpdate[container].state == "running")
|
for (let container in containersToUpdate){
|
||||||
continue;
|
container_id = containersToUpdate[container].id;
|
||||||
containersToUpdate[container].state = "running";
|
// check if container update stats is already running
|
||||||
|
if (containersToUpdate[container].state == "running")
|
||||||
|
continue;
|
||||||
|
containersToUpdate[container].state = "running";
|
||||||
|
|
||||||
|
|
||||||
window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) {
|
window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then(function(data) {
|
}).then(function(data) {
|
||||||
var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
|
var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
|
||||||
var netIOCtx = Chart.getChart(container + "_NetIOChart");
|
var netIOCtx = Chart.getChart(container + "_NetIOChart");
|
||||||
|
|
||||||
console.log(container);
|
console.log(container);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
prev_stats = null;
|
prev_stats = null;
|
||||||
if (data.length >= 2)
|
if (data.length >= 2)
|
||||||
prev_stats = data[data.length -2]
|
prev_stats = data[data.length -2]
|
||||||
data = data[data.length -1];
|
data = data[data.length -1];
|
||||||
|
|
||||||
if (prev_stats != null){
|
if (prev_stats != null){
|
||||||
// calc time diff
|
// calc time diff
|
||||||
var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000;
|
var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000;
|
||||||
|
|
||||||
// calc disk io b/s
|
// calc disk io b/s
|
||||||
var prev_read_bytes = 0;
|
if ('io_service_bytes_recursive' in prev_stats.blkio_stats && prev_stats.blkio_stats.io_service_bytes_recursive !== null){
|
||||||
var prev_write_bytes = 0;
|
var prev_read_bytes = 0;
|
||||||
for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){
|
var prev_write_bytes = 0;
|
||||||
if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read")
|
for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){
|
||||||
prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
|
if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read")
|
||||||
else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write")
|
prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
|
||||||
prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
|
else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write")
|
||||||
|
prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
|
||||||
|
}
|
||||||
|
var read_bytes = 0;
|
||||||
|
var write_bytes = 0;
|
||||||
|
for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){
|
||||||
|
if (data.blkio_stats.io_service_bytes_recursive[i].op == "read")
|
||||||
|
read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
|
||||||
|
else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write")
|
||||||
|
write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
|
||||||
|
}
|
||||||
|
var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff;
|
||||||
|
var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc net io b/s
|
||||||
|
if ('networks' in prev_stats){
|
||||||
|
var prev_recv_bytes = 0;
|
||||||
|
var prev_sent_bytes = 0;
|
||||||
|
for (var key in prev_stats.networks){
|
||||||
|
prev_recv_bytes += prev_stats.networks[key].rx_bytes;
|
||||||
|
prev_sent_bytes += prev_stats.networks[key].tx_bytes;
|
||||||
|
}
|
||||||
|
var recv_bytes = 0;
|
||||||
|
var sent_bytes = 0;
|
||||||
|
for (var key in data.networks){
|
||||||
|
recv_bytes += data.networks[key].rx_bytes;
|
||||||
|
sent_bytes += data.networks[key].tx_bytes;
|
||||||
|
}
|
||||||
|
var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff;
|
||||||
|
var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, "");
|
||||||
|
addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, "");
|
||||||
}
|
}
|
||||||
var read_bytes = 0;
|
|
||||||
var write_bytes = 0;
|
|
||||||
for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){
|
|
||||||
if (data.blkio_stats.io_service_bytes_recursive[i].op == "read")
|
|
||||||
read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
|
|
||||||
else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write")
|
|
||||||
write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
|
|
||||||
}
|
|
||||||
var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff;
|
|
||||||
var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff;
|
|
||||||
|
|
||||||
// calc net io b/s
|
// run again in n seconds
|
||||||
var prev_recv_bytes = 0;
|
containersToUpdate[container].state = "idle";
|
||||||
var prev_sent_bytes = 0;
|
}).catch(err => {
|
||||||
for (var key in prev_stats.networks){
|
console.log(err);
|
||||||
prev_recv_bytes += prev_stats.networks[key].rx_bytes;
|
});
|
||||||
prev_sent_bytes += prev_stats.networks[key].tx_bytes;
|
}
|
||||||
}
|
|
||||||
var recv_bytes = 0;
|
|
||||||
var sent_bytes = 0;
|
|
||||||
for (var key in data.networks){
|
|
||||||
recv_bytes += data.networks[key].rx_bytes;
|
|
||||||
sent_bytes += data.networks[key].tx_bytes;
|
|
||||||
}
|
|
||||||
var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff;
|
|
||||||
var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff;
|
|
||||||
|
|
||||||
addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, "");
|
|
||||||
addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
// run again in n seconds
|
|
||||||
containersToUpdate[container].state = "idle";
|
|
||||||
}).catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// run again in n seconds
|
// run again in n seconds
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 col-5 text-end">{{ lang.tfa.tfa }}:</div>
|
<div class="col-sm-3 col-5 text-end">{{ lang.tfa.tfa }}:</div>
|
||||||
<div class="col-sm-9 col-7">
|
<div class="col-sm-9 col-7">
|
||||||
<p id="tfa_pretty">{{ tfa_data.pretty }}</p>
|
|
||||||
{% include 'tfa_keys.twig' %}
|
{% include 'tfa_keys.twig' %}
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
@ -143,7 +143,8 @@
|
|||||||
updatedAt: '{{ mailcow_info.updatedAt }}',
|
updatedAt: '{{ mailcow_info.updatedAt }}',
|
||||||
project_url: '{{ mailcow_info.project_url }}',
|
project_url: '{{ mailcow_info.project_url }}',
|
||||||
project_owner: '{{ mailcow_info.project_owner }}',
|
project_owner: '{{ mailcow_info.project_owner }}',
|
||||||
project_repo: '{{ mailcow_info.project_repo }}'
|
project_repo: '{{ mailcow_info.project_repo }}',
|
||||||
|
branch: '{{ mailcow_info.mailcow_branch }}'
|
||||||
};
|
};
|
||||||
|
|
||||||
$(window).scroll(function() {
|
$(window).scroll(function() {
|
||||||
@ -202,7 +203,7 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
// Confirm TFA modal
|
// Confirm TFA modal
|
||||||
{% if pending_tfa_method %}
|
{% if pending_tfa_methods %}
|
||||||
new bootstrap.Modal(document.getElementById("ConfirmTFAModal"), {
|
new bootstrap.Modal(document.getElementById("ConfirmTFAModal"), {
|
||||||
backdrop: 'static',
|
backdrop: 'static',
|
||||||
keyboard: false
|
keyboard: false
|
||||||
@ -270,6 +271,11 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
|||||||
var id = $(this).children('input').first().val();
|
var id = $(this).children('input').first().val();
|
||||||
$("#webauthn_selected_id").val(id);
|
$("#webauthn_selected_id").val(id);
|
||||||
|
|
||||||
|
var webauthn_status_auth = document.getElementById('webauthn_status_auth');
|
||||||
|
webauthn_status_auth.style.setProperty('display', 'flex', 'important');
|
||||||
|
var webauthn_return_code = document.getElementById('webauthn_return_code');
|
||||||
|
webauthn_return_code.style.setProperty('display', 'none', 'important');
|
||||||
|
|
||||||
$("#collapseWebAuthnTFA").collapse('show');
|
$("#collapseWebAuthnTFA").collapse('show');
|
||||||
|
|
||||||
$(this).find('input[name=token]').focus();
|
$(this).find('input[name=token]').focus();
|
||||||
@ -307,8 +313,11 @@ function recursiveBase64StrToArrayBuffer(obj) {
|
|||||||
auth.value = AuthenticatorAttestationResponse;
|
auth.value = AuthenticatorAttestationResponse;
|
||||||
form.submit();
|
form.submit();
|
||||||
}).catch(function(err) {
|
}).catch(function(err) {
|
||||||
|
var webauthn_status_auth = document.getElementById('webauthn_status_auth');
|
||||||
|
webauthn_status_auth.style.setProperty('display', 'none', 'important');
|
||||||
|
|
||||||
var webauthn_return_code = document.getElementById('webauthn_return_code');
|
var webauthn_return_code = document.getElementById('webauthn_return_code');
|
||||||
webauthn_return_code.style.display = webauthn_return_code.style.display === 'none' ? '' : null;
|
webauthn_return_code.style.setProperty('display', 'block', 'important');
|
||||||
webauthn_return_code.innerHTML = lang_tfa.error_code + ': ' + err + ' ' + lang_tfa.reload_retry;
|
webauthn_return_code.innerHTML = lang_tfa.error_code + ': ' + err + ' ' + lang_tfa.reload_retry;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,14 @@
|
|||||||
<p id="mailcow_update"></p>
|
<p id="mailcow_update"></p>
|
||||||
</div></td>
|
</div></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if mailcow_info.mailcow_branch|lower == "master" %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Changelog</td>
|
<td>Changelog</td>
|
||||||
<td class="text-break"><a href="{{ mailcow_info.project_url }}/releases/tag/{{ mailcow_info.version_tag }}" target="_blank">
|
<td class="text-break"><a href="{{ mailcow_info.project_url }}/releases/tag/{{ mailcow_info.version_tag }}" target="_blank">
|
||||||
{{ mailcow_info.project_url }}/releases/tag/{{ mailcow_info.version_tag }}
|
{{ mailcow_info.project_url }}/releases/tag/{{ mailcow_info.version_tag }}
|
||||||
</a></td>
|
</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ lang.debug.current_time }}</td>
|
<td>{{ lang.debug.current_time }}</td>
|
||||||
<td id="host_date" class="text-break">-</td>
|
<td id="host_date" class="text-break">-</td>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
|
<label class="control-label col-sm-2" for="quota">{{ lang.edit.quota_mb }}
|
||||||
<br><span id="quotaBadge" class="badge">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
|
<br><span id="quotaBadge" class="badge bg-info">max. {{ (result.max_new_quota / 1048576) }} MiB</span>
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="number" name="quota" style="width:100%" min="0" max="{{ (result.max_new_quota / 1048576) }}" value="{{ (result.quota / 1048576) }}" class="form-control">
|
<input type="number" name="quota" style="width:100%" min="0" max="{{ (result.max_new_quota / 1048576) }}" value="{{ (result.quota / 1048576) }}" class="form-control">
|
||||||
|
@ -136,67 +136,176 @@
|
|||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button>
|
<h3 class="modal-title">{{ lang.tfa.tfa }}</h3>
|
||||||
<h3 class="modal-title">{{ lang.tfa[pending_tfa_method] }}</h3>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
|
||||||
{% if pending_tfa_method == 'yubi_otp' %}
|
|
||||||
<form role="form" method="post">
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-addon" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
|
|
||||||
<input type="text" name="token" class="form-control" autocomplete="off" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
|
|
||||||
<input type="hidden" name="tfa_method" value="yubi_otp">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-sm btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
{% if pending_tfa_method == 'totp' %}
|
|
||||||
<form role="form" method="post">
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group">
|
|
||||||
<span class="input-group-addon" id="tfa-addon"><i class="bi bi-shield-lock-fill"></i></span>
|
|
||||||
<input type="number" min="000000" max="999999" name="token" class="form-control" placeholder="123456" autocomplete="one-time-code" aria-describedby="tfa-addon">
|
|
||||||
<input type="hidden" name="tfa_method" value="totp">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-default" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
{% if pending_tfa_method == 'hotp' %}
|
|
||||||
<div class="empty"></div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if pending_tfa_method == 'webauthn' %}
|
|
||||||
<form role="form" method="post" id="webauthn_auth_form">
|
<div class="modal-body p-0 pt-4">
|
||||||
<center>
|
<ul class="nav nav-tabs px-1" id="tabContent">
|
||||||
<div style="cursor:pointer" id="start_webauthn_confirmation">
|
{% if pending_tfa_authmechs["webauthn"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24">
|
<li class="nav-item"><a class="nav-link active" href="#tfa_tab_webauthn" data-bs-toggle="tab" id="pending_tfa_tab_webauthn"><i class="bi bi-fingerprint"></i> WebAuthn</a></li>
|
||||||
<path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path>
|
{% endif %}
|
||||||
</svg>
|
|
||||||
<p>{{ lang.tfa.start_webauthn_validation }}</p>
|
{% if pending_tfa_authmechs["yubi_otp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
<hr>
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if pending_tfa_authmechs["yubi_otp"] %}active{% endif %}" href="#tfa_tab_yubi_otp" data-bs-toggle="tab" id="pending_tfa_tab_yubi_otp"><i class="bi bi-usb-drive"></i> Yubi OTP</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if pending_tfa_authmechs["totp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {% if pending_tfa_authmechs["totp"] %}active{% endif %}" href="#tfa_tab_totp" data-bs-toggle="tab" id="pending_tfa_tab_totp"><i class="bi bi-clock-history"></i> Time based OTP</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- <li class="nav-item"><a class="nav-link" href="#tfa_tab_hotp" data-bs-toggle="tab">HOTP</a></li> -->
|
||||||
|
{% if pending_tfa_authmechs["u2f"] is defined %}
|
||||||
|
<li class="nav-item"><a class="nav-link active" href="#tfa_tab_u2f" data-bs-toggle="tab"><i class="bi bi-x-octagon"></i> U2F</a></li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
{% if pending_tfa_authmechs["webauthn"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
|
<div role="tabpanel" class="tab-pane active" id="tfa_tab_webauthn">
|
||||||
|
<div class="card border-0" style="margin-bottom: 0px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<form role="form" method="post" id="webauthn_auth_form">
|
||||||
|
<legend class="mt-2 mb-2">
|
||||||
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
|
Authenticators
|
||||||
|
<hr />
|
||||||
|
</legend>
|
||||||
|
<div class="list-group">
|
||||||
|
{% for authenticator in pending_tfa_methods %}
|
||||||
|
{% if authenticator["authmech"] == "webauthn" %}
|
||||||
|
<a href="#" class="list-group-item webauthn-authenticator-selection">
|
||||||
|
<i class="bi bi-key-fill" style="margin-right: 5px"></i>
|
||||||
|
<span>{{ authenticator["key_id"] }}</span>
|
||||||
|
<input type="hidden" value="{{ authenticator["id"] }}" /><br/>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="collapse pending-tfa-collapse" id="collapseWebAuthnTFA">
|
||||||
|
<div class="row mt-4 mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="mt-4 d-flex align-items-center" id="webauthn_status_auth">
|
||||||
|
<div class="spinner-border me-2" role="status">
|
||||||
|
<span class="visually-hidden">Loading...</span>
|
||||||
|
</div>
|
||||||
|
{{ lang.tfa.init_webauthn }}
|
||||||
|
</div>
|
||||||
|
<div class="mt-4 alert alert-danger" style="display:none" id="webauthn_return_code"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="token" id="webauthn_auth_data"/>
|
||||||
|
<input type="hidden" name="tfa_method" value="webauthn">
|
||||||
|
<input type="hidden" name="verify_tfa_login"/>
|
||||||
|
<input type="hidden" name="id" id="webauthn_selected_id" /><br/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</center>
|
{% endif %}
|
||||||
<p id="webauthn_status_auth"></p>
|
{% if pending_tfa_authmechs["yubi_otp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
<div class="alert alert-danger" style="display:none" id="webauthn_return_code"></div>
|
<div role="tabpanel" class="tab-pane {% if pending_tfa_authmechs["yubi_otp"] %}active{% endif %}" id="tfa_tab_yubi_otp">
|
||||||
<input type="hidden" name="token" id="webauthn_auth_data"/>
|
<div class="card border-0" style="margin-bottom: 0px;">
|
||||||
<input type="hidden" name="tfa_method" value="webauthn">
|
<div class="card-body">
|
||||||
<input type="hidden" name="verify_tfa_login"/><br/>
|
<form role="form" method="post">
|
||||||
</form>
|
<legend class="mt-2 mb-2">
|
||||||
{% endif %}
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
{# leave this here to inform users that u2f is deprecated #}
|
Authenticate
|
||||||
{% if pending_tfa_method == 'u2f' %}
|
<hr />
|
||||||
<form role="form" method="post" id="u2f_auth_form">
|
</legend>
|
||||||
<p>{{ lang.tfa.u2f_deprecated }}</p>
|
<div class="collapse show pending-tfa-collapse" id="collapseYubiTFA">
|
||||||
<p><b>{{ lang.tfa.u2f_deprecated_important }}</b></p>
|
<div class="row mt-4 mb-4">
|
||||||
<input type="hidden" name="token" value="destroy" />
|
<div class="col-12">
|
||||||
<input type="hidden" name="tfa_method" value="u2f">
|
<div class="input-group mt-4">
|
||||||
<input type="hidden" name="verify_tfa_login"/><br/>
|
<span class="input-group-text" id="yubi-addon"><img alt="Yubicon Icon" src="/img/yubi.ico"></span>
|
||||||
<button type="submit" class="btn btn-xs-lg btn-success" value="Login">{{ lang.login.login }}</button>
|
<input type="text" name="token" class="form-control" autocomplete="off" placeholder="Touch Yubikey" aria-describedby="yubi-addon">
|
||||||
</form>
|
<input type="hidden" name="tfa_method" value="yubi_otp">
|
||||||
{% endif %}
|
<input type="hidden" name="id" id="yubi_selected_id" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-secondary" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if pending_tfa_authmechs["totp"] is defined and pending_tfa_authmechs["u2f"] is not defined %}
|
||||||
|
<div role="tabpanel" class="tab-pane {% if pending_tfa_authmechs["totp"] %}active{% endif %}" id="tfa_tab_totp">
|
||||||
|
<div class="card border-0" style="margin-bottom: 0px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<form role="form" method="post">
|
||||||
|
<legend class="mt-2 mb-2">
|
||||||
|
<i class="bi bi-shield-fill-check"></i>
|
||||||
|
Authenticators
|
||||||
|
<hr />
|
||||||
|
</legend>
|
||||||
|
<div class="list-group">
|
||||||
|
{% for authenticator in pending_tfa_methods %}
|
||||||
|
{% if authenticator["authmech"] == "totp" %}
|
||||||
|
<a href="#" class="list-group-item totp-authenticator-selection">
|
||||||
|
<i class="bi bi-key-fill" style="margin-right: 5px"></i>
|
||||||
|
<span>{{ authenticator["key_id"] }}</span>
|
||||||
|
<input type="hidden" value="{{ authenticator["id"] }}" />
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="collapse pending-tfa-collapse" id="collapseTotpTFA">
|
||||||
|
<div class="row mt-4 mb-4">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="input-group mt-4">
|
||||||
|
<span class="input-group-text" id="tfa-addon"><i class="bi bi-shield-lock-fill"></i></span>
|
||||||
|
<input type="number" min="000000" max="999999" name="token" class="form-control" placeholder="123456" autocomplete="one-time-code" aria-describedby="tfa-addon">
|
||||||
|
<input type="hidden" name="tfa_method" value="totp">
|
||||||
|
<input type="hidden" name="id" id="totp_selected_id" /><br/>
|
||||||
|
</div>
|
||||||
|
<button class="mt-4 btn btn-sm visible-xs-block visible-sm-inline visible-md-inline visible-lg-inline btn-secondary" type="submit" name="verify_tfa_login">{{ lang.login.login }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<!--
|
||||||
|
<div role="tabpanel" class="tab-pane" id="tfa_tab_hotp">
|
||||||
|
<div class="card" style="margin-bottom: 0px;">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="empty"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
{% if pending_tfa_authmechs["u2f"] is defined %}
|
||||||
|
<div role="tabpanel" class="tab-pane active" id="tfa_tab_u2f">
|
||||||
|
<div class="card border-0" style="margin-bottom: 0px;">
|
||||||
|
<div class="card-body">
|
||||||
|
{# leave this here to inform users that u2f is deprecated #}
|
||||||
|
<form role="form" method="post" id="u2f_auth_form">
|
||||||
|
<div>
|
||||||
|
<p>{{ lang.tfa.u2f_deprecated }}</p>
|
||||||
|
<p><b>{{ lang.tfa.u2f_deprecated_important }}</b></p>
|
||||||
|
<input type="hidden" name="token" value="destroy" />
|
||||||
|
<input type="hidden" name="tfa_method" value="u2f">
|
||||||
|
<input type="hidden" name="verify_tfa_login"/><br/>
|
||||||
|
<button type="submit" class="btn btn-xs-lg btn-success" value="Login">{{ lang.login.login }}</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
{% for key_info in tfa_data.additional %}
|
{% for key_info in tfa_data.additional %}
|
||||||
<form style="display:inline;" method="post">
|
<form style="display:inline;" method="post">
|
||||||
<input type="hidden" name="unset_tfa_key" value="{{ key_info.id }}">
|
<input type="hidden" name="unset_tfa_key" value="{{ key_info.id }}">
|
||||||
<p>
|
<div class="d-flex flex-column">
|
||||||
<span style="padding:4px;margin:4px" class="badge fs-6 bg-{% if tfa_id == key_info.id %}success{% else %}dark{% endif %}">
|
<span style="padding:4px;margin:4px" class="me-auto badge fs-6 bg-{% if tfa_id == key_info.id %}success{% else %}dark{% endif %}">
|
||||||
{{ key_info.key_id }}
|
{{ key_info.key_id }}
|
||||||
<a href="#" class="btn p-0 text-white" style="font-size: 12px; line-height: 1rem;" onClick='return confirm("{{ lang.admin.ays }}")?$(this).closest("form").submit():"";'>[{{ lang.admin.remove }}]</a>
|
<a href="#" class="btn p-0 text-white" style="font-size: 12px; line-height: 1rem;" onClick='return confirm("{{ lang.admin.ays }}")?$(this).closest("form").submit():"";'>[{{ lang.admin.remove }}]</a>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.set_tfa }}:</div>
|
<div class="col-sm-3 col-xs-5 text-right">{{ lang.tfa.set_tfa }}:</div>
|
||||||
<div class="col-sm-9 col-xs-7">
|
<div class="col-sm-9 col-xs-7">
|
||||||
<select data-style="btn btn-sm dropdown-toggle bs-placeholder btn-default" data-width="fit" id="selectTFA" class="selectpicker" title="{{ lang.tfa.select }}">
|
<select data-style="btn btn-sm dropdown-toggle bs-placeholder btn-secondary" data-width="fit" id="selectTFA" class="selectpicker" title="{{ lang.tfa.select }}">
|
||||||
<option value="yubi_otp">{{ lang.tfa.yubi_otp }}</option>
|
<option value="yubi_otp">{{ lang.tfa.yubi_otp }}</option>
|
||||||
<option value="webauthn">{{ lang.tfa.webauthn }}</option>
|
<option value="webauthn">{{ lang.tfa.webauthn }}</option>
|
||||||
<option value="totp">{{ lang.tfa.totp }}</option>
|
<option value="totp">{{ lang.tfa.totp }}</option>
|
||||||
|
Loading…
Reference in New Issue
Block a user