-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidator.py
More file actions
58 lines (48 loc) · 1.92 KB
/
Copy pathvalidator.py
File metadata and controls
58 lines (48 loc) · 1.92 KB
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
import sqlite3
import re
import logging
from schema import get_schema
logging.basicConfig(filename='error_log.txt', level=logging.ERROR, format='%(asctime)s - %(message)s')
def validate_and_execute(sql):
conn = sqlite3.connect('data.db')
if not sql.strip().upper().startswith('SELECT'):
msg = 'Only SELECT allowed'
logging.error(msg)
conn.close()
return None, msg
match = re.search(r'FROM\s+(\w+)', sql, re.IGNORECASE)
if not match:
msg = 'No table found'
logging.error(msg)
conn.close()
return None, msg
table = match.group(1)
cursor = conn.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table,))
if not cursor.fetchone():
msg = f'Table {table} not found'
logging.error(msg)
conn.close()
return None, msg
valid_cols = [col['name'] for col in get_schema(table)]
valid_cols_lower = [c.lower() for c in valid_cols]
# Skip column check if SELECT *
if '*' not in sql:
# Find column names (letters and underscores, not SQL keywords)
keywords = {'select', 'from', 'where', 'and', 'or', 'not', 'in', 'like', 'order', 'by', 'group', 'limit', 'join', 'on', 'as', 'null', 'true', 'false', 'inner', 'left', 'right'}
words = re.findall(r'\b[a-z_][a-z0-9_]*\b', sql.lower())
potential_cols = [w for w in words if w not in keywords and not w.isdigit()]
for col in potential_cols:
if col not in valid_cols_lower:
msg = f"Column '{col}' not found in table {table}"
logging.error(msg)
conn.close()
return None, msg
try:
cursor = conn.execute(sql)
results = cursor.fetchall()
conn.close()
return results, 'Success'
except Exception as e:
logging.error(str(e))
conn.close()
return None, str(e)