fix(packs-lab): 누락된 A1-A3 파일 복구 (Dockerfile + auth + DSM client + tests)
Tasks A1-A3 의 파일이 working tree에 있었으나 git에 stage되지 않은 상태에서
A4 commit이 진행되어 routes.py 의 import (auth, dsm_client)가 깨진 상태였음.
복구: 8 files 일괄 commit.
- packs-lab/Dockerfile
- packs-lab/app/__init__.py
- packs-lab/app/requirements.txt
- packs-lab/app/auth.py (HMAC verify_request_hmac + verify_upload_token)
- packs-lab/app/dsm_client.py (DSM 7.x Sharing.create wrapper)
- packs-lab/tests/{__init__.py, test_auth.py}
- packs-lab/pytest.ini
This commit is contained in:
85
packs-lab/tests/test_auth.py
Normal file
85
packs-lab/tests/test_auth.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""HMAC 인증 단위 테스트.
|
||||
|
||||
- verify_request_hmac: Vercel ↔ backend 요청 시그니처 검증
|
||||
- verify_upload_token: 일회성 업로드 토큰 검증 (jti 단발성)
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
# 환경변수 먼저 세팅 (auth import 전)
|
||||
os.environ["BACKEND_HMAC_SECRET"] = "test-secret-32-bytes-XXXXXXXXXXXX"
|
||||
|
||||
from app import auth # noqa: E402
|
||||
|
||||
|
||||
def test_verify_request_hmac_valid():
|
||||
body = b'{"file_path":"/x"}'
|
||||
ts = str(int(time.time()))
|
||||
sig = auth._sign(ts.encode() + b"." + body)
|
||||
auth.verify_request_hmac(body, ts, sig) # 예외 X
|
||||
|
||||
|
||||
def test_verify_request_hmac_expired():
|
||||
body = b'{}'
|
||||
old_ts = str(int(time.time()) - 600) # 10분 전
|
||||
sig = auth._sign(old_ts.encode() + b"." + body)
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
auth.verify_request_hmac(body, old_ts, sig)
|
||||
assert exc.value.status_code == 401
|
||||
|
||||
|
||||
def test_verify_request_hmac_wrong_sig():
|
||||
body = b'{}'
|
||||
ts = str(int(time.time()))
|
||||
with pytest.raises(HTTPException):
|
||||
auth.verify_request_hmac(body, ts, "deadbeef")
|
||||
|
||||
|
||||
def test_upload_token_roundtrip():
|
||||
payload = {
|
||||
"tier": "master",
|
||||
"label": "샘플 영상",
|
||||
"filename": "sample.mp4",
|
||||
"size_bytes": 1024,
|
||||
"expires_at": int(time.time()) + 600,
|
||||
"jti": uuid.uuid4().hex,
|
||||
}
|
||||
token = auth.mint_upload_token(payload)
|
||||
decoded = auth.verify_upload_token(token)
|
||||
assert decoded["filename"] == "sample.mp4"
|
||||
assert decoded["jti"] == payload["jti"]
|
||||
|
||||
|
||||
def test_upload_token_replay_rejected():
|
||||
payload = {
|
||||
"tier": "starter",
|
||||
"label": "x",
|
||||
"filename": "y.pdf",
|
||||
"size_bytes": 1,
|
||||
"expires_at": int(time.time()) + 600,
|
||||
"jti": uuid.uuid4().hex,
|
||||
}
|
||||
token = auth.mint_upload_token(payload)
|
||||
auth.verify_upload_token(token) # 첫 사용 OK
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
auth.verify_upload_token(token) # 재사용
|
||||
assert "이미" in exc.value.detail or "used" in exc.value.detail.lower()
|
||||
|
||||
|
||||
def test_upload_token_expired():
|
||||
payload = {
|
||||
"tier": "starter",
|
||||
"label": "x",
|
||||
"filename": "y.pdf",
|
||||
"size_bytes": 1,
|
||||
"expires_at": int(time.time()) - 100,
|
||||
"jti": uuid.uuid4().hex,
|
||||
}
|
||||
token = auth.mint_upload_token(payload)
|
||||
with pytest.raises(HTTPException):
|
||||
auth.verify_upload_token(token)
|
||||
Reference in New Issue
Block a user