mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 21:36:52 +08:00
feat(security): enhance password validation and API key handling
- Strengthen password requirements with checks for uppercase, lowercase, numbers, and special characters (at least 3 types required) - Block access to sensitive configuration files like qbm_settings.yml - Improve API key display in UI with password input and show/hide toggle for better security
This commit is contained in:
parent
0dd5be6fdd
commit
8aa0751c74
4 changed files with 32 additions and 9 deletions
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
4.6.1-develop20
|
4.6.1-develop21
|
||||||
|
|
|
@ -93,8 +93,25 @@ class SecuritySettingsRequest(BaseModel):
|
||||||
|
|
||||||
@validator("password")
|
@validator("password")
|
||||||
def password_must_be_strong(cls, v):
|
def password_must_be_strong(cls, v):
|
||||||
if v and len(v) < 8:
|
if v:
|
||||||
raise ValueError("Password must be at least 8 characters")
|
if len(v) < 8:
|
||||||
|
raise ValueError("Password must be at least 8 characters")
|
||||||
|
|
||||||
|
# Check for character type requirements
|
||||||
|
has_upper = bool(re.search(r"[A-Z]", v))
|
||||||
|
has_lower = bool(re.search(r"[a-z]", v))
|
||||||
|
has_number = bool(re.search(r"\d", v))
|
||||||
|
has_special = bool(re.search(r"[!@#$%^&*]", v))
|
||||||
|
|
||||||
|
# Count how many character types are present
|
||||||
|
type_count = sum([has_upper, has_lower, has_number, has_special])
|
||||||
|
|
||||||
|
if type_count < 3:
|
||||||
|
raise ValueError(
|
||||||
|
"Password must contain at least 3 of: uppercase letters, "
|
||||||
|
"lowercase letters, numbers, special characters (!@#$%^&*)"
|
||||||
|
)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@validator("method")
|
@validator("method")
|
||||||
|
|
|
@ -746,6 +746,10 @@ class WebAPI:
|
||||||
# Validate filename to prevent path traversal and block sensitive files
|
# Validate filename to prevent path traversal and block sensitive files
|
||||||
config_file_path = self._validate_config_filename(filename)
|
config_file_path = self._validate_config_filename(filename)
|
||||||
|
|
||||||
|
# Explicitly block access to sensitive settings file
|
||||||
|
if filename == "qbm_settings.yml":
|
||||||
|
raise HTTPException(status_code=403, detail="Access to settings file is forbidden")
|
||||||
|
|
||||||
if not config_file_path.exists():
|
if not config_file_path.exists():
|
||||||
raise HTTPException(status_code=404, detail=f"Configuration file '{filename}' not found")
|
raise HTTPException(status_code=404, detail=f"Configuration file '{filename}' not found")
|
||||||
|
|
||||||
|
@ -1669,11 +1673,6 @@ class WebAPI:
|
||||||
|
|
||||||
# Don't return sensitive information for security
|
# Don't return sensitive information for security
|
||||||
settings.password_hash = "***" if settings.password_hash else ""
|
settings.password_hash = "***" if settings.password_hash else ""
|
||||||
# Show only last 4 characters of API key for verification
|
|
||||||
if settings.api_key:
|
|
||||||
settings.api_key = f"***{settings.api_key[-4:]}" if len(settings.api_key) > 4 else "***"
|
|
||||||
else:
|
|
||||||
settings.api_key = ""
|
|
||||||
|
|
||||||
return settings
|
return settings
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -134,7 +134,14 @@ export class SecurityComponent {
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="api-key-display" class="form-label">API Key</label>
|
<label for="api-key-display" class="form-label">API Key</label>
|
||||||
<div class="api-key-input-group">
|
<div class="api-key-input-group">
|
||||||
<input type="text" id="api-key-display" class="form-input" readonly value="${this.currentSettings.api_key || ''}" placeholder="No API key generated">
|
<div class="password-input-group">
|
||||||
|
<input type="password" id="api-key-display" class="form-input" readonly value="${this.currentSettings.api_key || ''}" placeholder="No API key generated">
|
||||||
|
${this.currentSettings.api_key ? `
|
||||||
|
<button type="button" class="btn btn-icon password-toggle" data-target="api-key-display" title="Show full API key">
|
||||||
|
${EYE_ICON_SVG}
|
||||||
|
</button>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
<button type="button" class="btn btn-secondary" id="generate-api-key">
|
<button type="button" class="btn btn-secondary" id="generate-api-key">
|
||||||
${this.currentSettings.api_key ? 'Generate New Key' : 'Generate Key'}
|
${this.currentSettings.api_key ? 'Generate New Key' : 'Generate Key'}
|
||||||
</button>
|
</button>
|
||||||
|
|
Loading…
Add table
Reference in a new issue