File size: 4,406 Bytes
0f3460d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
"""

Input Validation Utilities

μž…λ ₯κ°’ 검증 및 sanitization



SQL Injection λ°©μ§€λ₯Ό μœ„ν•œ μΆ”κ°€ 검증 λ ˆμ΄μ–΄

"""
import re
from typing import Any, List, Optional
from fastapi import HTTPException


# UUID v4 μ •κ·œμ‹
UUID_PATTERN = re.compile(
    r'^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$',
    re.IGNORECASE
)


def validate_uuid(value: str, field_name: str = "id") -> str:
    """

    UUID ν˜•μ‹ 검증



    Args:

        value: 검증할 κ°’

        field_name: ν•„λ“œ 이름 (μ—λŸ¬ λ©”μ‹œμ§€μš©)



    Returns:

        κ²€μ¦λœ UUID λ¬Έμžμ—΄



    Raises:

        HTTPException: UUID ν˜•μ‹μ΄ μ•„λ‹Œ 경우

    """
    if not value or not isinstance(value, str):
        raise HTTPException(
            status_code=400,
            detail=f"{field_name} must be a valid UUID"
        )

    value = value.strip().lower()

    if not UUID_PATTERN.match(value):
        raise HTTPException(
            status_code=400,
            detail=f"{field_name} must be a valid UUID format"
        )

    return value


def validate_user_id(user_id: str) -> str:
    """

    μ‚¬μš©μž ID 검증 (UUID ν˜•μ‹)



    Args:

        user_id: μ‚¬μš©μž ID



    Returns:

        κ²€μ¦λœ user_id

    """
    return validate_uuid(user_id, "user_id")


def validate_ids(ids: List[str], field_name: str = "ids") -> List[str]:
    """

    μ—¬λŸ¬ UUID 검증



    Args:

        ids: UUID 리슀트

        field_name: ν•„λ“œ 이름



    Returns:

        κ²€μ¦λœ UUID 리슀트

    """
    if not ids or not isinstance(ids, list):
        raise HTTPException(
            status_code=400,
            detail=f"{field_name} must be a non-empty list"
        )

    if len(ids) > 100:
        raise HTTPException(
            status_code=400,
            detail=f"{field_name} list too large (max 100)"
        )

    return [validate_uuid(id_val, field_name) for id_val in ids]


def sanitize_string(value: str, max_length: int = 1000) -> str:
    """

    λ¬Έμžμ—΄ sanitization



    Args:

        value: μž…λ ₯ λ¬Έμžμ—΄

        max_length: μ΅œλŒ€ 길이



    Returns:

        μ •μ œλœ λ¬Έμžμ—΄

    """
    if not value or not isinstance(value, str):
        return ""

    # μ•žλ’€ 곡백 제거
    value = value.strip()

    # 길이 μ œν•œ
    if len(value) > max_length:
        value = value[:max_length]

    # μ œμ–΄ 문자 제거 (μ€„λ°”κΏˆ, νƒ­ μ œμ™Έ)
    value = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', value)

    return value


def validate_pagination(

    limit: int,

    offset: int,

    max_limit: int = 100

) -> tuple[int, int]:
    """

    νŽ˜μ΄μ§€λ„€μ΄μ…˜ νŒŒλΌλ―Έν„° 검증



    Args:

        limit: 쑰회 개수

        offset: μ‹œμž‘ μœ„μΉ˜

        max_limit: μ΅œλŒ€ limit κ°’



    Returns:

        (limit, offset) νŠœν”Œ

    """
    if limit < 1:
        limit = 10
    if limit > max_limit:
        limit = max_limit

    if offset < 0:
        offset = 0

    return limit, offset


def validate_enum(

    value: str,

    allowed_values: List[str],

    field_name: str = "value"

) -> str:
    """

    Enum κ°’ 검증



    Args:

        value: 검증할 κ°’

        allowed_values: ν—ˆμš©λœ κ°’ λͺ©λ‘

        field_name: ν•„λ“œ 이름



    Returns:

        κ²€μ¦λœ κ°’

    """
    if not value or value not in allowed_values:
        raise HTTPException(
            status_code=400,
            detail=f"{field_name} must be one of: {', '.join(allowed_values)}"
        )

    return value


def validate_coordinates(lat: float, lng: float) -> tuple[float, float]:
    """

    μ’Œν‘œ μœ νš¨μ„± 검증



    Args:

        lat: μœ„λ„

        lng: 경도



    Returns:

        (lat, lng) νŠœν”Œ

    """
    if not isinstance(lat, (int, float)) or not isinstance(lng, (int, float)):
        raise HTTPException(
            status_code=400,
            detail="Coordinates must be numeric"
        )

    if not -90 <= lat <= 90:
        raise HTTPException(
            status_code=400,
            detail="Latitude must be between -90 and 90"
        )

    if not -180 <= lng <= 180:
        raise HTTPException(
            status_code=400,
            detail="Longitude must be between -180 and 180"
        )

    return lat, lng