security: fix 5 review findings (2 high, 3 medium)

HIGH:
- Lock setup TOTP/NAS endpoints behind _require_setup() guard
  (prevented unauthenticated admin 2FA takeover after setup)
- Sanitize upload filename with Path().name + resolve() validation
  (prevented path traversal writing outside Inbox)

MEDIUM:
- Add score > 0.01 filter to hybrid search via subquery
  (prevented returning irrelevant documents with zero score)
- Implement Inbox → Knowledge file move after classification
  (classify_worker now moves files based on ai_domain)
- Add Anthropic Messages API support in _request()
  (premium/Claude path now sends correct format and parses
  content[0].text instead of choices[0].message.content)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-04-02 15:33:31 +09:00
parent 31d5498f8d
commit d93e50b55c
5 changed files with 114 additions and 37 deletions

View File

@@ -154,8 +154,7 @@ async def totp_init(
session: Annotated[AsyncSession, Depends(get_session)],
):
"""TOTP 시크릿 생성 + otpauth URI 반환 (DB에 저장하지 않음)"""
# 셋업 중이거나 인증된 유저만 사용 가능
# 셋업 중에는 admin 생성 직후 호출됨
await _require_setup(session)
secret = pyotp.random_base32()
totp = pyotp.TOTP(secret)
uri = totp.provisioning_uri(
@@ -171,7 +170,7 @@ async def totp_verify(
session: Annotated[AsyncSession, Depends(get_session)],
):
"""TOTP 코드 검증 후 DB에 시크릿 저장"""
# 코드 검증
await _require_setup(session)
totp = pyotp.TOTP(body.secret)
if not totp.verify(body.code):
raise HTTPException(
@@ -194,8 +193,12 @@ async def totp_verify(
@router.post("/verify-nas", response_model=VerifyNASResponse)
async def verify_nas(body: VerifyNASRequest):
async def verify_nas(
body: VerifyNASRequest,
session: Annotated[AsyncSession, Depends(get_session)],
):
"""NAS 마운트 경로 읽기/쓰기 테스트"""
await _require_setup(session)
path = Path(body.path)
exists = path.exists()
readable = path.is_dir() and any(True for _ in path.iterdir()) if exists else False