File size: 2,682 Bytes
24ea8aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Input validation utilities for audio uploads and text sanitization.
"""

import re
import logging
from functools import wraps
from flask import request, jsonify

logger = logging.getLogger(__name__)

# Patterns commonly used in prompt injection attempts
_INJECTION_PATTERNS = [
    re.compile(r'ignore\s+(all\s+)?previous\s+instructions', re.IGNORECASE),
    re.compile(r'ignore\s+(all\s+)?above\s+instructions', re.IGNORECASE),
    re.compile(r'^system\s*:', re.IGNORECASE | re.MULTILINE),
    re.compile(r'you\s+are\s+now\s+(?:a|an|the)\s+', re.IGNORECASE),
    re.compile(r'pretend\s+(?:you\s+are|to\s+be)', re.IGNORECASE),
    re.compile(r'act\s+as\s+(?:a|an|if)', re.IGNORECASE),
    re.compile(r'new\s+instructions?\s*:', re.IGNORECASE),
    re.compile(r'disregard\s+(?:all\s+)?(?:previous|prior|above)', re.IGNORECASE),
]


def validate_audio_upload(field_name='audio'):
    """Decorator to validate audio file uploads.

    Checks that a file is present, not empty, and within size limits.
    Returns 400 JSON on validation failure.
    """
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if request.method == 'OPTIONS':
                return f(*args, **kwargs)

            if field_name not in request.files:
                return jsonify({'success': False, 'error': f'No {field_name} file provided'}), 400

            audio_file = request.files[field_name]

            if not audio_file.filename:
                return jsonify({'success': False, 'error': 'Empty filename'}), 400

            # Check file size (read content length from stream)
            audio_file.seek(0, 2)  # seek to end
            file_size = audio_file.tell()
            audio_file.seek(0)  # reset to beginning

            if file_size < 100:
                return jsonify({'success': False, 'error': 'Audio file too small (possibly empty recording)'}), 400

            if file_size > 30 * 1024 * 1024:  # 30MB
                return jsonify({'success': False, 'error': 'Audio file too large. Maximum size is 30MB.'}), 400

            return f(*args, **kwargs)
        return wrapper
    return decorator


def sanitize_text_for_llm(text, max_length=5000):
    """Sanitize user-provided text before passing to LLM.

    Truncates to max_length and strips common prompt injection patterns.
    """
    if not text:
        return ''

    # Truncate
    text = text[:max_length]

    # Strip injection patterns
    for pattern in _INJECTION_PATTERNS:
        text = pattern.sub('', text)

    # Remove excessive whitespace that could result from stripping
    text = re.sub(r'\n{3,}', '\n\n', text)
    text = text.strip()

    return text