mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-09 05:18:03 +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")
|
||||
def password_must_be_strong(cls, v):
|
||||
if v and len(v) < 8:
|
||||
raise ValueError("Password must be at least 8 characters")
|
||||
if v:
|
||||
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
|
||||
|
||||
@validator("method")
|
||||
|
|
|
@ -746,6 +746,10 @@ class WebAPI:
|
|||
# Validate filename to prevent path traversal and block sensitive files
|
||||
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():
|
||||
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
|
||||
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
|
||||
except Exception as e:
|
||||
|
|
|
@ -134,7 +134,14 @@ export class SecurityComponent {
|
|||
<div class="form-group">
|
||||
<label for="api-key-display" class="form-label">API Key</label>
|
||||
<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">
|
||||
${this.currentSettings.api_key ? 'Generate New Key' : 'Generate Key'}
|
||||
</button>
|
||||
|
|
Loading…
Add table
Reference in a new issue