fix: LLDP port label bug, suppression SQL dead code, avatar path hardening
Lint / Python (flake8) (push) Successful in 1m13s
Lint / JS (eslint) (push) Successful in 7s
Security / Python Security (bandit) (push) Successful in 42s
Test / Python Tests (pytest) (push) Successful in 50s
Lint / Notify on failure (push) Has been skipped
Lint / Deploy (push) Successful in 3s
Lint / Python (flake8) (push) Successful in 1m13s
Lint / JS (eslint) (push) Successful in 7s
Security / Python Security (bandit) (push) Successful in 42s
Test / Python Tests (pytest) (push) Successful in 50s
Lint / Notify on failure (push) Has been skipped
Lint / Deploy (push) Successful in 3s
- inspector.html: fix LLDP neighbor label in port blocks — port.lldp_table never exists; data is at port.lldp (dict with system_name/chassis_id); both port block renderers corrected - db.py: remove dead 'target_detail IS NULL' branch in suppression check — target_detail is always stored as '' not NULL; query simplified to target_detail='' - app.py: resolve cache_dir/cache_file/sentinel to absolute paths; guard against path escape before use - app.py: wrap sentinel os.path.getmtime() in try/except OSError to handle TOCTOU deletion race Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -539,10 +539,16 @@ def api_avatar():
|
|||||||
|
|
||||||
# Build a safe cache filename from the username (alphanumeric + - _ .)
|
# Build a safe cache filename from the username (alphanumeric + - _ .)
|
||||||
safe_name = re.sub(r'[^a-zA-Z0-9._-]', '_', username)
|
safe_name = re.sub(r'[^a-zA-Z0-9._-]', '_', username)
|
||||||
cache_dir = ldap_cfg.get('cache_dir', os.path.join(tempfile.gettempdir(), 'gandalf_avatars'))
|
cache_dir = os.path.abspath(
|
||||||
|
ldap_cfg.get('cache_dir', os.path.join(tempfile.gettempdir(), 'gandalf_avatars'))
|
||||||
|
)
|
||||||
os.makedirs(cache_dir, exist_ok=True)
|
os.makedirs(cache_dir, exist_ok=True)
|
||||||
cache_file = os.path.join(cache_dir, f'user_{safe_name}.jpg')
|
cache_file = os.path.abspath(os.path.join(cache_dir, f'user_{safe_name}.jpg'))
|
||||||
sentinel = os.path.join(cache_dir, f'user_{safe_name}.none')
|
sentinel = os.path.abspath(os.path.join(cache_dir, f'user_{safe_name}.none'))
|
||||||
|
# Guard against path escape (shouldn't happen with sanitised safe_name, but be explicit)
|
||||||
|
if not cache_file.startswith(cache_dir + os.sep) or not sentinel.startswith(cache_dir + os.sep):
|
||||||
|
logger.error(f'Avatar path escape detected for user {username!r}')
|
||||||
|
return '', 404
|
||||||
try:
|
try:
|
||||||
cache_ttl = int(ldap_cfg.get('cache_ttl', 3600))
|
cache_ttl = int(ldap_cfg.get('cache_ttl', 3600))
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
@@ -557,8 +563,11 @@ def api_avatar():
|
|||||||
max_age=cache_ttl, conditional=True)
|
max_age=cache_ttl, conditional=True)
|
||||||
|
|
||||||
# Skip LDAP if we already know this user has no avatar
|
# Skip LDAP if we already know this user has no avatar
|
||||||
if os.path.exists(sentinel) and now - os.path.getmtime(sentinel) < cache_ttl:
|
try:
|
||||||
return '', 404
|
if os.path.exists(sentinel) and now - os.path.getmtime(sentinel) < cache_ttl:
|
||||||
|
return '', 404
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
# Query lldap
|
# Query lldap
|
||||||
bind_pw = ldap_cfg.get('bind_pw', '')
|
bind_pw = ldap_cfg.get('bind_pw', '')
|
||||||
|
|||||||
@@ -365,7 +365,7 @@ def is_suppressed(target_type: str, target_name: str, target_detail: str = '') -
|
|||||||
"""SELECT id FROM suppression_rules
|
"""SELECT id FROM suppression_rules
|
||||||
WHERE active=TRUE AND (expires_at IS NULL OR expires_at > NOW())
|
WHERE active=TRUE AND (expires_at IS NULL OR expires_at > NOW())
|
||||||
AND target_type=%s AND target_name=%s
|
AND target_type=%s AND target_name=%s
|
||||||
AND (target_detail IS NULL OR target_detail='') LIMIT 1""",
|
AND target_detail='' LIMIT 1""",
|
||||||
(target_type, target_name),
|
(target_type, target_name),
|
||||||
)
|
)
|
||||||
if cur.fetchone():
|
if cur.fetchone():
|
||||||
|
|||||||
@@ -107,10 +107,8 @@ function portBlockHtml(idx, port, swName, sfpBlock) {
|
|||||||
const sfpCls = sfpBlock ? ' sfp-block' : '';
|
const sfpCls = sfpBlock ? ' sfp-block' : '';
|
||||||
const speedTxt = portSpeedLabel(port);
|
const speedTxt = portSpeedLabel(port);
|
||||||
// LLDP neighbor: first 6 chars of hostname
|
// LLDP neighbor: first 6 chars of hostname
|
||||||
const lldpName = (port && port.lldp_table && port.lldp_table.length)
|
const lldpName = (port && port.lldp && (port.lldp.system_name || port.lldp.chassis_id))
|
||||||
? escHtml((port.lldp_table[0].chassis_id_subtype === 'local'
|
? escHtml((port.lldp.system_name || port.lldp.chassis_id || '').slice(0, 6))
|
||||||
? port.lldp_table[0].chassis_id
|
|
||||||
: port.lldp_table[0].system_name || port.lldp_table[0].chassis_id || '').slice(0, 6))
|
|
||||||
: '';
|
: '';
|
||||||
const lldpHtml = lldpName ? `<span class="port-lldp">${lldpName}</span>` : '';
|
const lldpHtml = lldpName ? `<span class="port-lldp">${lldpName}</span>` : '';
|
||||||
const speedHtml = speedTxt ? `<span class="port-speed">${speedTxt}</span>` : '';
|
const speedHtml = speedTxt ? `<span class="port-speed">${speedTxt}</span>` : '';
|
||||||
@@ -162,10 +160,8 @@ function renderChassis(swName, sw) {
|
|||||||
const state = portBlockState(port);
|
const state = portBlockState(port);
|
||||||
const title = port ? escHtml(port.name) : `Port ${idx}`;
|
const title = port ? escHtml(port.name) : `Port ${idx}`;
|
||||||
const speedTxt = portSpeedLabel(port);
|
const speedTxt = portSpeedLabel(port);
|
||||||
const lldpName = (port && port.lldp_table && port.lldp_table.length)
|
const lldpName = (port && port.lldp && (port.lldp.system_name || port.lldp.chassis_id))
|
||||||
? escHtml((port.lldp_table[0].chassis_id_subtype === 'local'
|
? escHtml((port.lldp.system_name || port.lldp.chassis_id || '').slice(0, 6))
|
||||||
? port.lldp_table[0].chassis_id
|
|
||||||
: port.lldp_table[0].system_name || port.lldp_table[0].chassis_id || '').slice(0, 6))
|
|
||||||
: '';
|
: '';
|
||||||
const speedHtml = speedTxt ? `<span class="port-speed">${speedTxt}</span>` : '';
|
const speedHtml = speedTxt ? `<span class="port-speed">${speedTxt}</span>` : '';
|
||||||
const lldpHtml = lldpName ? `<span class="port-lldp">${lldpName}</span>` : '';
|
const lldpHtml = lldpName ? `<span class="port-lldp">${lldpName}</span>` : '';
|
||||||
|
|||||||
Reference in New Issue
Block a user