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
86 lines
2.4 KiB
Python
86 lines
2.4 KiB
Python
"""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)
|