Skip to content

Commit 18cd6d4

Browse files
committed
security
1 parent 218be9c commit 18cd6d4

File tree

2 files changed

+272
-19
lines changed

2 files changed

+272
-19
lines changed

frontend/static/css/style.css

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,6 +1455,132 @@ label .info-icon ~ text {
14551455
margin-bottom: 15px;
14561456
}
14571457

1458+
/* Tag input system for malicious file detection */
1459+
.tag-input-container {
1460+
background: #1f2937;
1461+
border: 1px solid rgba(90, 109, 137, 0.3);
1462+
border-radius: 8px;
1463+
padding: 10px;
1464+
min-height: 100px;
1465+
max-height: 200px;
1466+
overflow-y: auto;
1467+
}
1468+
1469+
.tag-list {
1470+
display: flex;
1471+
flex-wrap: wrap;
1472+
gap: 8px;
1473+
margin-bottom: 10px;
1474+
min-height: 32px;
1475+
}
1476+
1477+
.tag-item {
1478+
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%);
1479+
border: 1px solid rgba(90, 109, 137, 0.4);
1480+
border-radius: 6px;
1481+
padding: 6px 10px;
1482+
display: flex;
1483+
align-items: center;
1484+
gap: 8px;
1485+
color: #e5e7eb;
1486+
font-size: 13px;
1487+
font-weight: 500;
1488+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
1489+
transition: all 0.2s ease;
1490+
}
1491+
1492+
.tag-item:hover {
1493+
background: linear-gradient(135deg, #1d4ed8 0%, #2563eb 100%);
1494+
border-color: rgba(90, 109, 137, 0.6);
1495+
transform: translateY(-1px);
1496+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
1497+
}
1498+
1499+
.tag-remove {
1500+
background: none;
1501+
border: none;
1502+
color: #ef4444;
1503+
cursor: pointer;
1504+
padding: 0;
1505+
width: 16px;
1506+
height: 16px;
1507+
display: flex;
1508+
align-items: center;
1509+
justify-content: center;
1510+
border-radius: 50%;
1511+
font-size: 12px;
1512+
transition: all 0.2s ease;
1513+
}
1514+
1515+
.tag-remove:hover {
1516+
background: rgba(239, 68, 68, 0.2);
1517+
color: #fca5a5;
1518+
transform: scale(1.1);
1519+
}
1520+
1521+
.tag-input-wrapper {
1522+
display: flex;
1523+
gap: 8px;
1524+
align-items: center;
1525+
}
1526+
1527+
.tag-input {
1528+
flex: 1;
1529+
background: #374151;
1530+
border: 1px solid rgba(90, 109, 137, 0.2);
1531+
border-radius: 6px;
1532+
padding: 8px 12px;
1533+
color: #e5e7eb;
1534+
font-size: 14px;
1535+
outline: none;
1536+
transition: all 0.2s ease;
1537+
}
1538+
1539+
.tag-input:focus {
1540+
border-color: rgba(90, 109, 137, 0.5);
1541+
background: #4b5563;
1542+
box-shadow: 0 0 0 3px rgba(90, 109, 137, 0.1);
1543+
}
1544+
1545+
.tag-input::placeholder {
1546+
color: #9ca3af;
1547+
}
1548+
1549+
.tag-add-btn {
1550+
background: linear-gradient(135deg, #065f46 0%, #059669 100%);
1551+
border: 1px solid rgba(90, 109, 137, 0.3);
1552+
border-radius: 6px;
1553+
padding: 8px 12px;
1554+
color: #d1fae5;
1555+
cursor: pointer;
1556+
display: flex;
1557+
align-items: center;
1558+
justify-content: center;
1559+
min-width: 40px;
1560+
transition: all 0.2s ease;
1561+
}
1562+
1563+
.tag-add-btn:hover {
1564+
background: linear-gradient(135deg, #047857 0%, #10b981 100%);
1565+
border-color: rgba(90, 109, 137, 0.5);
1566+
transform: translateY(-1px);
1567+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
1568+
}
1569+
1570+
.tag-add-btn:active {
1571+
transform: translateY(0);
1572+
}
1573+
1574+
/* Empty state for tag lists */
1575+
.tag-list:empty::before {
1576+
content: "No items added yet";
1577+
color: #6b7280;
1578+
font-style: italic;
1579+
font-size: 13px;
1580+
padding: 8px 0;
1581+
display: block;
1582+
}
1583+
14581584
.instance-header {
14591585
display: flex;
14601586
align-items: center;

frontend/static/js/settings_forms.js

Lines changed: 146 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,25 +1172,41 @@ const SettingsForms = {
11721172
</div>
11731173
11741174
<div class="setting-item">
1175-
<label for="swaparr_malicious_extensions">
1175+
<label for="swaparr_malicious_extensions_input">
11761176
<a href="https://plexguide.github.io/Huntarr.io/apps/swaparr.html#malicious-extensions" class="info-icon" title="File extensions to consider malicious" target="_blank" rel="noopener">
11771177
<i class="fas fa-info-circle"></i>
11781178
</a>
11791179
Malicious File Extensions:
11801180
</label>
1181-
<textarea id="swaparr_malicious_extensions" rows="3" placeholder="Enter file extensions separated by commas...">${(settings.malicious_extensions || ['.lnk', '.exe', '.bat', '.cmd', '.scr', '.zipx', '.jar', '.vbs']).join(', ')}</textarea>
1182-
<p class="setting-help">File extensions to block (comma-separated). Examples: .lnk, .exe, .bat, .zipx</p>
1181+
<div class="tag-input-container">
1182+
<div class="tag-list" id="swaparr_malicious_extensions_tags"></div>
1183+
<div class="tag-input-wrapper">
1184+
<input type="text" id="swaparr_malicious_extensions_input" placeholder="Type extension and press Enter (e.g. .lnk)" class="tag-input">
1185+
<button type="button" class="tag-add-btn" onclick="addExtensionTag()">
1186+
<i class="fas fa-plus"></i>
1187+
</button>
1188+
</div>
1189+
</div>
1190+
<p class="setting-help">File extensions to block. Type extension and press Enter or click +. Examples: .lnk, .exe, .bat, .zipx</p>
11831191
</div>
11841192
11851193
<div class="setting-item">
1186-
<label for="swaparr_suspicious_patterns">
1194+
<label for="swaparr_suspicious_patterns_input">
11871195
<a href="https://plexguide.github.io/Huntarr.io/apps/swaparr.html#suspicious-patterns" class="info-icon" title="Suspicious filename patterns" target="_blank" rel="noopener">
11881196
<i class="fas fa-info-circle"></i>
11891197
</a>
11901198
Suspicious Patterns:
11911199
</label>
1192-
<textarea id="swaparr_suspicious_patterns" rows="3" placeholder="Enter suspicious patterns separated by commas...">${(settings.suspicious_patterns || ['password.txt', 'readme.txt', 'install.exe', 'keygen', 'crack']).join(', ')}</textarea>
1193-
<p class="setting-help">Filename patterns to block (comma-separated). Examples: password.txt, keygen, crack</p>
1200+
<div class="tag-input-container">
1201+
<div class="tag-list" id="swaparr_suspicious_patterns_tags"></div>
1202+
<div class="tag-input-wrapper">
1203+
<input type="text" id="swaparr_suspicious_patterns_input" placeholder="Type pattern and press Enter (e.g. keygen)" class="tag-input">
1204+
<button type="button" class="tag-add-btn" onclick="addPatternTag()">
1205+
<i class="fas fa-plus"></i>
1206+
</button>
1207+
</div>
1208+
</div>
1209+
<p class="setting-help">Filename patterns to block. Type pattern and press Enter or click +. Examples: password.txt, keygen, crack</p>
11941210
</div>
11951211
</div>
11961212
@@ -1213,6 +1229,9 @@ const SettingsForms = {
12131229
}
12141230
});
12151231
}
1232+
1233+
// Initialize tag systems
1234+
this.initializeTagSystem(settings);
12161235

12171236
// Add event listener for global Swaparr enabled toggle to control instance visibility
12181237
const swaparrEnabledToggle = container.querySelector('#swaparr_enabled');
@@ -1230,6 +1249,124 @@ const SettingsForms = {
12301249
}
12311250
},
12321251

1252+
// Initialize tag input systems for malicious file detection
1253+
initializeTagSystem: function(settings) {
1254+
// Initialize extensions
1255+
const defaultExtensions = ['.lnk', '.exe', '.bat', '.cmd', '.scr', '.pif', '.com', '.zipx', '.jar', '.vbs', '.js', '.jse', '.wsf', '.wsh'];
1256+
const extensions = settings.malicious_extensions || defaultExtensions;
1257+
this.loadTags('swaparr_malicious_extensions_tags', extensions);
1258+
1259+
// Initialize patterns
1260+
const defaultPatterns = ['password.txt', 'readme.txt', 'install.exe', 'setup.exe', 'keygen', 'crack', 'patch.exe', 'activator'];
1261+
const patterns = settings.suspicious_patterns || defaultPatterns;
1262+
this.loadTags('swaparr_suspicious_patterns_tags', patterns);
1263+
1264+
// Add enter key listeners
1265+
const extensionInput = document.getElementById('swaparr_malicious_extensions_input');
1266+
const patternInput = document.getElementById('swaparr_suspicious_patterns_input');
1267+
1268+
if (extensionInput) {
1269+
extensionInput.addEventListener('keypress', (e) => {
1270+
if (e.key === 'Enter') {
1271+
e.preventDefault();
1272+
this.addExtensionTag();
1273+
}
1274+
});
1275+
}
1276+
1277+
if (patternInput) {
1278+
patternInput.addEventListener('keypress', (e) => {
1279+
if (e.key === 'Enter') {
1280+
e.preventDefault();
1281+
this.addPatternTag();
1282+
}
1283+
});
1284+
}
1285+
1286+
// Make functions globally accessible
1287+
window.addExtensionTag = () => this.addExtensionTag();
1288+
window.addPatternTag = () => this.addPatternTag();
1289+
},
1290+
1291+
// Load tags into a tag list
1292+
loadTags: function(containerId, tags) {
1293+
const container = document.getElementById(containerId);
1294+
if (!container) return;
1295+
1296+
container.innerHTML = '';
1297+
tags.forEach(tag => {
1298+
this.createTagElement(container, tag);
1299+
});
1300+
},
1301+
1302+
// Create a tag element
1303+
createTagElement: function(container, text) {
1304+
const tagDiv = document.createElement('div');
1305+
tagDiv.className = 'tag-item';
1306+
tagDiv.innerHTML = `
1307+
<span class="tag-text">${text}</span>
1308+
<button type="button" class="tag-remove" onclick="this.parentElement.remove()">
1309+
<i class="fas fa-times"></i>
1310+
</button>
1311+
`;
1312+
container.appendChild(tagDiv);
1313+
},
1314+
1315+
// Add extension tag
1316+
addExtensionTag: function() {
1317+
const input = document.getElementById('swaparr_malicious_extensions_input');
1318+
const container = document.getElementById('swaparr_malicious_extensions_tags');
1319+
1320+
if (!input || !container) return;
1321+
1322+
let value = input.value.trim();
1323+
if (!value) return;
1324+
1325+
// Auto-add dot if not present for extensions
1326+
if (!value.startsWith('.')) {
1327+
value = '.' + value;
1328+
}
1329+
1330+
// Check for duplicates
1331+
const existing = Array.from(container.querySelectorAll('.tag-text')).map(el => el.textContent);
1332+
if (existing.includes(value)) {
1333+
input.value = '';
1334+
return;
1335+
}
1336+
1337+
this.createTagElement(container, value);
1338+
input.value = '';
1339+
},
1340+
1341+
// Add pattern tag
1342+
addPatternTag: function() {
1343+
const input = document.getElementById('swaparr_suspicious_patterns_input');
1344+
const container = document.getElementById('swaparr_suspicious_patterns_tags');
1345+
1346+
if (!input || !container) return;
1347+
1348+
const value = input.value.trim();
1349+
if (!value) return;
1350+
1351+
// Check for duplicates
1352+
const existing = Array.from(container.querySelectorAll('.tag-text')).map(el => el.textContent);
1353+
if (existing.includes(value)) {
1354+
input.value = '';
1355+
return;
1356+
}
1357+
1358+
this.createTagElement(container, value);
1359+
input.value = '';
1360+
},
1361+
1362+
// Get tags from a container
1363+
getTagsFromContainer: function(containerId) {
1364+
const container = document.getElementById(containerId);
1365+
if (!container) return [];
1366+
1367+
return Array.from(container.querySelectorAll('.tag-text')).map(el => el.textContent);
1368+
},
1369+
12331370
// Generate Hunt Manager placeholder form
12341371
generateHuntingForm: function(container, settings = {}) {
12351372
// Add data-app-type attribute to container
@@ -1611,19 +1748,9 @@ const SettingsForms = {
16111748
// Malicious file detection settings
16121749
settings.malicious_file_detection = getInputValue('#swaparr_malicious_detection', false);
16131750

1614-
// Parse malicious extensions (comma-separated)
1615-
const extensionsText = document.getElementById('swaparr_malicious_extensions')?.value || '';
1616-
settings.malicious_extensions = extensionsText
1617-
.split(',')
1618-
.map(ext => ext.trim())
1619-
.filter(ext => ext.length > 0);
1620-
1621-
// Parse suspicious patterns (comma-separated)
1622-
const patternsText = document.getElementById('swaparr_suspicious_patterns')?.value || '';
1623-
settings.suspicious_patterns = patternsText
1624-
.split(',')
1625-
.map(pattern => pattern.trim())
1626-
.filter(pattern => pattern.length > 0);
1751+
// Get tags from tag containers
1752+
settings.malicious_extensions = this.getTagsFromContainer('swaparr_malicious_extensions_tags');
1753+
settings.suspicious_patterns = this.getTagsFromContainer('swaparr_suspicious_patterns_tags');
16271754
}
16281755
}
16291756

0 commit comments

Comments
 (0)