mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/caddy: widgets, hide unused certs, improve error handling (#4372)
* www/caddy: CaddyCertificate widget, compare certs on disk with configured hostnames and only display relevant ones * www/caddy: Caddy Domain widget improve error handling
This commit is contained in:
@@ -17,6 +17,8 @@ Plugin Changelog
|
||||
|
||||
* Add: Layer4 TLS Termination
|
||||
* Add: h2c protocol to HTTP Handler
|
||||
* Cleanup: Caddy Certificate widget hides unused automatic certificates
|
||||
* Cleanup: Widgets error handling improved
|
||||
* Cleanup: Refactor caddy_certs.php to Trust model
|
||||
|
||||
1.7.4
|
||||
|
||||
@@ -38,8 +38,8 @@ export default class CaddyCertificate extends BaseTableWidget {
|
||||
}
|
||||
|
||||
getMarkup() {
|
||||
let $container = $('<div></div>');
|
||||
let $caddyCertificateTable = this.createTable('caddyCertificateTable', {
|
||||
const $container = $('<div></div>');
|
||||
const $caddyCertificateTable = this.createTable('caddyCertificateTable', {
|
||||
headerPosition: 'none'
|
||||
});
|
||||
|
||||
@@ -48,49 +48,54 @@ export default class CaddyCertificate extends BaseTableWidget {
|
||||
}
|
||||
|
||||
async onWidgetTick() {
|
||||
// Check if Caddy is enabled
|
||||
const caddyStatus = await this.ajaxCall('/api/caddy/reverse_proxy/get');
|
||||
if (!caddyStatus.caddy.general || caddyStatus.caddy.general.enabled === "0") {
|
||||
const proxyData = await this.ajaxCall('/api/caddy/reverse_proxy/get');
|
||||
if (!proxyData.caddy.general || proxyData.caddy.general.enabled === "0") {
|
||||
this.displayError(`${this.translations.unconfigured}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the certificate details
|
||||
const response = await this.ajaxCall('/api/caddy/diagnostics/certificate');
|
||||
if (response.status !== "success") {
|
||||
const domains = Object.values(proxyData.caddy.reverseproxy?.reverse || [])
|
||||
.map(proxy => proxy.FromDomain)
|
||||
.filter(Boolean);
|
||||
|
||||
const certificates = (await this.ajaxCall('/api/caddy/diagnostics/certificate')).content || [];
|
||||
|
||||
// Display certificate if hostname in config and CN of stored cert on disk match
|
||||
const matchingCertificates = certificates.filter(cert => domains.includes(cert.hostname));
|
||||
|
||||
if (matchingCertificates.length === 0) {
|
||||
this.displayError(`${this.translations.nocerts}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process certificates if the response is successful
|
||||
this.processCertificates(response.content);
|
||||
this.clearError();
|
||||
this.processCertificates(matchingCertificates);
|
||||
}
|
||||
|
||||
// Utility function to display errors within the widget
|
||||
displayError(message) {
|
||||
const $error = $(`<div class="error-message"><a href="/ui/caddy/general">${message}</a></div>`);
|
||||
$('#caddyCertificateTable').empty().append($error);
|
||||
}
|
||||
|
||||
processCertificates(certificates) {
|
||||
if (!this.dataChanged('certificates', certificates)) {
|
||||
return;
|
||||
}
|
||||
clearError() {
|
||||
$('#caddyCertificateTable .error-message').remove();
|
||||
}
|
||||
|
||||
processCertificates(certificates) {
|
||||
$('.caddy-certificate-tooltip').tooltip('hide');
|
||||
|
||||
let rows = certificates.map(certificate => {
|
||||
let colorClass = 'text-success';
|
||||
if (certificate.remaining_days === 0) {
|
||||
colorClass = 'text-danger';
|
||||
} else if (certificate.remaining_days < 14) {
|
||||
colorClass = 'text-warning';
|
||||
}
|
||||
const rows = certificates.map(certificate => {
|
||||
const colorClass = certificate.remaining_days === 0
|
||||
? 'text-danger'
|
||||
: certificate.remaining_days < 14
|
||||
? 'text-warning'
|
||||
: 'text-success';
|
||||
|
||||
let statusText = certificate.remaining_days === 0 ? this.translations.expired :
|
||||
this.translations.valid;
|
||||
const statusText = certificate.remaining_days === 0
|
||||
? this.translations.expired
|
||||
: this.translations.valid;
|
||||
|
||||
let row = `
|
||||
const row = `
|
||||
<div>
|
||||
<i class="fa fa-lock ${colorClass} caddy-certificate-tooltip" style="cursor: pointer;"
|
||||
data-tooltip="caddy-certificate-${certificate.hostname}" title="${statusText}">
|
||||
@@ -98,19 +103,19 @@ export default class CaddyCertificate extends BaseTableWidget {
|
||||
|
||||
<span><b>${certificate.hostname}</b></span>
|
||||
<br/>
|
||||
<div style="margin-top: 5px; margin-bottom: 5px;"><i>${this.translations.expires}</i> ${certificate.remaining_days} ${this.translations.days}, ${new Date(certificate.expiration_date).toLocaleString()}</div>
|
||||
<div style="margin-top: 5px; margin-bottom: 5px;">
|
||||
<i>${this.translations.expires}</i> ${certificate.remaining_days} ${this.translations.days},
|
||||
${new Date(certificate.expiration_date).toLocaleString()}
|
||||
</div>
|
||||
</div>`;
|
||||
return { html: row, expirationDate: new Date(certificate.expiration_date) };
|
||||
});
|
||||
|
||||
// Sort rows by expiration date from lowest to highest
|
||||
rows.sort((a, b) => a.expirationDate - b.expirationDate);
|
||||
|
||||
// Extract sorted HTML rows and update table
|
||||
let sortedRows = rows.map(row => [row.html]);
|
||||
const sortedRows = rows.map(row => [row.html]);
|
||||
super.updateTable('caddyCertificateTable', sortedRows);
|
||||
|
||||
// Initialize tooltips for new elements
|
||||
$('.caddy-certificate-tooltip').tooltip({container: 'body'});
|
||||
$('.caddy-certificate-tooltip').tooltip({ container: 'body' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ export default class CaddyDomain extends BaseTableWidget {
|
||||
}
|
||||
|
||||
getMarkup() {
|
||||
let $container = $('<div></div>');
|
||||
let $caddyDomainTable = this.createTable('caddyDomainTable', {
|
||||
const $container = $('<div></div>');
|
||||
const $caddyDomainTable = this.createTable('caddyDomainTable', {
|
||||
headerPosition: 'none'
|
||||
});
|
||||
|
||||
@@ -55,7 +55,14 @@ export default class CaddyDomain extends BaseTableWidget {
|
||||
}
|
||||
|
||||
// Process domains if caddy is enabled
|
||||
let domains = { ...data.caddy.reverseproxy.reverse, ...data.caddy.reverseproxy.subdomain };
|
||||
const domains = { ...data.caddy.reverseproxy.reverse, ...data.caddy.reverseproxy.subdomain };
|
||||
|
||||
if (Object.keys(domains).length === 0) {
|
||||
this.displayError(`${this.translations.nodomains}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearError();
|
||||
this.processDomains(domains);
|
||||
}
|
||||
|
||||
@@ -65,6 +72,10 @@ export default class CaddyDomain extends BaseTableWidget {
|
||||
$('#caddyDomainTable').empty().append($error);
|
||||
}
|
||||
|
||||
clearError() {
|
||||
$('#caddyDomainTable .error-message').remove();
|
||||
}
|
||||
|
||||
processDomains(domains) {
|
||||
if (!this.dataChanged('domains', domains)) {
|
||||
return;
|
||||
@@ -72,19 +83,18 @@ export default class CaddyDomain extends BaseTableWidget {
|
||||
|
||||
$('.caddy-domain-tooltip').tooltip('hide');
|
||||
|
||||
let rows = [];
|
||||
// Assuming domains is a combination of both reverse and subdomains
|
||||
const rows = [];
|
||||
for (const key in domains) {
|
||||
const domain = domains[key];
|
||||
let colorClass = domain.enabled === "1" ? 'text-success' : 'text-danger';
|
||||
let tooltipText = domain.enabled === "1" ? this.translations.enabled : this.translations.disabled;
|
||||
const colorClass = domain.enabled === "1" ? 'text-success' : 'text-danger';
|
||||
const tooltipText = domain.enabled === "1" ? this.translations.enabled : this.translations.disabled;
|
||||
let domainPort = domain.FromDomain;
|
||||
|
||||
if (domain.FromPort) {
|
||||
domainPort += `:${domain.FromPort}`;
|
||||
}
|
||||
|
||||
let row = $(`
|
||||
const row = $(`
|
||||
<div class="caddy-info">
|
||||
<div class="caddy-enabled">
|
||||
<i class="fa fa-globe ${colorClass} caddy-domain-tooltip" style="cursor: pointer;"
|
||||
@@ -108,6 +118,6 @@ export default class CaddyDomain extends BaseTableWidget {
|
||||
super.updateTable('caddyDomainTable', rows.map(row => [row.html]));
|
||||
|
||||
// Initialize tooltips for interactivity
|
||||
$('.caddy-domain-tooltip').tooltip({container: 'body'});
|
||||
$('.caddy-domain-tooltip').tooltip({ container: 'body' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<enabled>Enabled</enabled>
|
||||
<disabled>Disabled</disabled>
|
||||
<unconfigured>Caddy is disabled or not configured.</unconfigured>
|
||||
<nodomains>Caddy does not manage any domains.</nodomains>
|
||||
</translations>
|
||||
</caddydomain>
|
||||
<caddycertificate>
|
||||
|
||||
Reference in New Issue
Block a user