-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Expand file tree
/
Copy pathtstrings.py
More file actions
78 lines (64 loc) · 2.3 KB
/
tstrings.py
File metadata and controls
78 lines (64 loc) · 2.3 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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from dataclasses import dataclass
from string.templatelib import Interpolation, Template, convert
from typing import Any
@dataclass(frozen=True)
class SQLQuery:
statement: str
params: list[Any]
def __init__(self, template: Template) -> None:
items, params = [], []
for item in template:
match item:
case str():
items.append(item)
case Interpolation(value, _, conversion, format_spec):
converted = convert(value, conversion)
if format_spec:
converted = format(converted, format_spec)
params.append(converted)
items.append("?")
super().__setattr__("statement", "".join(items))
super().__setattr__("params", params)
def find_users_query_v1(name: str) -> str:
"""Return a SQL query to find users by name."""
return f"SELECT * FROM users WHERE name = '{name}'"
# Uncomment for Python 3.14:
#
# def find_users_query_v2(name: str) -> Template:
# """Return a SQL query to find users by name."""
# return t"SELECT * FROM users WHERE name = '{name}'"
#
#
# def find_users(name: str) -> SQLQuery:
# """Return a SQL query to find users by name."""
# return SQLQuery(t"SELECT * FROM users WHERE name = {name}")
def render(template: Template) -> str:
return "".join(
f"{text}{value}"
for text, value in zip(template.strings, template.values)
)
def safer_render(template: Template) -> str:
items = []
for item in template:
if isinstance(item, str):
items.append(item)
else:
sanitized = str(item.value).replace("'", "''")
items.append(sanitized)
return "".join(items)
if __name__ == "__main__":
# Insecure f-strings
print(find_users_query_v1("' OR '1'='1"))
# Uncomment for Python 3.14:
#
# # More secure t-strings
# print(find_users_query_v2("' OR '1'='1"))
#
# # Insecure way of rendering t-strings into plain strings
# print(render(find_users_query_v2("' OR '1'='1")))
#
# # More secure way of rendering t-strings
# print(safer_render(find_users_query_v2("' OR '1'='1")))
#
# # Rendering t-strings into an alternative representation
# print(find_users("' OR '1'='1"))