Compare commits

..

6 Commits

Author SHA1 Message Date
wmantly f0ceb750a8 Merge pull request #145 from theta42/bump-version
chore: bump version to 1.19.3
2026-08-02 14:06:20 -04:00
wmantly 6e95defcf5 chore: bump version to 1.19.3 2026-08-02 14:02:00 -04:00
wmantly 92c2e8a03b Merge pull request #144 from theta42/fix/discovery-edges
fix: resolve discovery and UI bugs
2026-08-02 13:23:56 -04:00
wmantly 230e5be2fd fix: regex syntax error in proxmox plugin 2026-08-02 13:20:15 -04:00
wmantly 0331cb976a fix: resolve discovery and UI bugs 2026-08-02 12:55:19 -04:00
wmantly 90cf65e920 Merge pull request #143 from theta42/fix/discovery-edges
fix: process edges during discovery reconciliation
2026-08-02 12:10:04 -04:00
7 changed files with 27 additions and 11 deletions
Binary file not shown.
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "t42-sso-manager", "name": "t42-sso-manager",
"version": "1.19.2", "version": "1.19.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "t42-sso-manager", "name": "t42-sso-manager",
"version": "1.19.2", "version": "1.19.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^7.3.0", "@fortawesome/fontawesome-free": "^7.3.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "t42-sso-manager", "name": "t42-sso-manager",
"version": "1.19.2", "version": "1.19.3",
"description": "A very simple LDAP management and SSO system", "description": "A very simple LDAP management and SSO system",
"author": [ "author": [
{ {
+7 -5
View File
@@ -31,17 +31,19 @@ module.exports = {
if (!targetRange) throw new Error("Missing targetRange for Nmap"); if (!targetRange) throw new Error("Missing targetRange for Nmap");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const scan = new nmap.OsAndPortScan(targetRange); // OsAndPortScan requires root (for -O). NmapScan does a basic port scan (TCP connect if non-root).
const scan = new nmap.NmapScan(targetRange);
scan.command.push('-Pn'); scan.command.push('-Pn');
scan.on('complete', function(data) { scan.on('complete', function(data) {
const resources = []; const resources = [];
const edges = []; const edges = [];
for (const host of data) { for (const host of data) {
if (!host.mac || !host.ip) continue; if (!host.ip) continue;
const hostSlug = `nmap-host-${host.mac.replace(/:/g, '')}`; const hostId = host.mac ? host.mac.replace(/:/g, '') : host.ip.replace(/\\./g, '_');
const hostSlug = `nmap-host-${hostId}`;
const interfaces = [{ mac: host.mac, ip: host.ip }]; const interfaces = [{ mac: host.mac || null, ip: host.ip }];
resources.push({ resources.push({
kind: 'host', kind: 'host',
@@ -52,7 +54,7 @@ module.exports = {
if (host.openPorts && host.openPorts.length > 0) { if (host.openPorts && host.openPorts.length > 0) {
for (const port of host.openPorts) { for (const port of host.openPorts) {
const svcSlug = `nmap-svc-${host.mac.replace(/:/g, '')}-${port.port}`; const svcSlug = `nmap-svc-${hostId}-${port.port}`;
resources.push({ resources.push({
kind: 'service', kind: 'service',
name: `${port.service} on ${port.port}`, name: `${port.service} on ${port.port}`,
+3
View File
@@ -43,6 +43,9 @@ module.exports = {
const headers = { const headers = {
'Authorization': `PVEAPIToken=${tokenId}=${tokenSecret}` 'Authorization': `PVEAPIToken=${tokenId}=${tokenSecret}`
}; };
// Ensure URL has no trailing slash
url = url.endsWith('/') ? url.slice(0, -1) : url;
const resources = []; const resources = [];
const edges = []; const edges = [];
+1 -1
View File
@@ -164,7 +164,7 @@
return; return;
} }
$('.actionMessage').html('<div class="alert alert-success alert-dismissible"><button type="button" class="btn-close" data-bs-dismiss="alert"></button>Successfully promoted! Created groups: ' + res.groups.join(', ') + '</div>').show(); $('.actionMessage').html('<div class="alert alert-success alert-dismissible"><button type="button" class="btn-close" data-bs-dismiss="alert"></button>Successfully promoted! Created groups: ' + res.groups.join(', ') + '</div>').show();
renderTable(); loadResources();
}); });
} }
+13 -2
View File
@@ -57,6 +57,7 @@
<button class="btn btn-sm btn-warning" title="Edit Secrets" onclick="openSecretsModal('{{id}}')"><i class="fa-solid fa-key"></i></button> <button class="btn btn-sm btn-warning" title="Edit Secrets" onclick="openSecretsModal('{{id}}')"><i class="fa-solid fa-key"></i></button>
<button class="btn btn-sm btn-info" title="Test" onclick="testPlugin('{{id}}')"><i class="fa-solid fa-vial"></i></button> <button class="btn btn-sm btn-info" title="Test" onclick="testPlugin('{{id}}')"><i class="fa-solid fa-vial"></i></button>
<button class="btn btn-sm btn-success" title="Run now" onclick="runNow('{{id}}')"><i class="fa-solid fa-play"></i></button> <button class="btn btn-sm btn-success" title="Run now" onclick="runNow('{{id}}')"><i class="fa-solid fa-play"></i></button>
{{#lastError}}<button class="btn btn-sm btn-secondary" title="View Logs" onclick="showLogs('{{id}}')"><i class="fa-solid fa-file-lines"></i></button>{{/lastError}}
{{#enabled}}<button class="btn btn-sm btn-outline-danger" title="Unload" onclick="togglePlugin('{{id}}', false)">Unload</button>{{/enabled}} {{#enabled}}<button class="btn btn-sm btn-outline-danger" title="Unload" onclick="togglePlugin('{{id}}', false)">Unload</button>{{/enabled}}
{{^enabled}}<button class="btn btn-sm btn-outline-success" title="Load" onclick="togglePlugin('{{id}}', true)">Load</button>{{/enabled}} {{^enabled}}<button class="btn btn-sm btn-outline-success" title="Load" onclick="togglePlugin('{{id}}', true)">Load</button>{{/enabled}}
<button class="btn btn-sm btn-outline-danger" title="Delete" onclick="deletePlugin('{{id}}')"><i class="fa-solid fa-trash"></i></button> <button class="btn btn-sm btn-outline-danger" title="Delete" onclick="deletePlugin('{{id}}')"><i class="fa-solid fa-trash"></i></button>
@@ -280,7 +281,7 @@
'<div class="form-text">Secret fields are edited separately with the <i class="fa-solid fa-key"></i> button.</div>', '<div class="form-text">Secret fields are edited separately with the <i class="fa-solid fa-key"></i> button.</div>',
footer: { footer: {
metaHtml: app.modal.formatAudit ? app.modal.formatAudit(p, { formatDate: function(ms){ return moment(ms).format('YYYY-MM-DD HH:mm'); } }) : '', metaHtml: app.modal.formatAudit ? app.modal.formatAudit(p, { formatDate: function(ms){ return moment(ms).format('YYYY-MM-DD HH:mm'); } }) : '',
buttonsHtml: app.modal.footerButtons({ onSave: 'saveEdit("' + id + '")', saveLabel: 'Save' }) buttonsHtml: app.modal.footerButtons({ onSave: 'saveEdit(\'' + id + '\')', saveLabel: 'Save' })
} }
}); });
} }
@@ -324,7 +325,7 @@
app.modal.open({ app.modal.open({
title: 'Edit Secrets — ' + p.name, title: 'Edit Secrets — ' + p.name,
bodyHtml: html, bodyHtml: html,
footer: { buttonsHtml: app.modal.footerButtons({ onSave: 'saveSecrets("' + id + '")', saveLabel: 'Save Secrets' }) } footer: { buttonsHtml: app.modal.footerButtons({ onSave: 'saveSecrets(\'' + id + '\')', saveLabel: 'Save Secrets' }) }
}); });
} }
@@ -369,6 +370,16 @@
} }
} }
function showLogs(id) {
var p = pluginsById[id];
if (!p || !p.lastError) return;
app.modal.open({
title: 'Logs — ' + p.name,
bodyHtml: '<pre class="bg-dark text-white p-3 rounded" style="white-space: pre-wrap; font-size: 0.85em;">' + String(p.lastError).replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</pre>',
footer: { buttonsHtml: '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>' }
});
}
async function togglePlugin(id, enable) { async function togglePlugin(id, enable) {
try { try {
await app.api.post('plugins/' + id + (enable ? '/load' : '/unload'), {}); await app.api.post('plugins/' + id + (enable ? '/load' : '/unload'), {});