Skip to content

Commit 16b9401

Browse files
authored
Merge pull request #3 from truethari/alpha
version 1.2 Fixed: Possible SQL injection vector through string-based query construction
2 parents 16c9ec1 + a78a296 commit 16b9401

File tree

3 files changed

+72
-76
lines changed

3 files changed

+72
-76
lines changed

ReallySimpleDB/manager.py

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,37 @@
44
from .utils import DATA_TYPES
55

66
class ReallySimpleDB:
7-
""" ReallySimpleDB class
7+
"""
8+
ReallySimpleDB class.
89
910
ReallySimpleDB objects are the ones responsible of creating DBs, connecting
1011
with them, creating tables, adding records, geting records, among tasks. In
1112
more cases these should be one per database.
1213
"""
1314

1415
def __init__(self) -> None:
15-
"""
16-
create a object
17-
"""
16+
"""Create a object."""
1817
self._add_columns_cmd = ""
1918
self.connection = ""
2019

2120
def clean(self):
2221
"""
23-
cleans add_columns data
22+
Clean add_columns data.
2423
25-
why? _add_columns_cmd variable is for define SQL command. when using add_column,
24+
Why? _add_columns_cmd variable is for define SQL command. when using add_column,
2625
it sets up a string here. but when it is finished this is not clean and the data
2726
continues to exist. when use add_column again and again, it will be processed
2827
along with the existing data. this should be used to prevent it.
2928
"""
3029
self._add_columns_cmd = ""
3130

3231
def create_connection(self, database):
33-
"""opens a connection to the SQLite database file"""
32+
"""Open a connection to the SQLite database file."""
3433
self.connection = sqlite3.connect(database)
3534
return True
3635

3736
def create_db(self, dbpath:str="", replace:bool=False):
38-
"""creates a new database in a given path"""
37+
"""Create a new database in a given path."""
3938
if self.connection == "" and not dbpath:
4039
raise TypeError("create_db() missing 1 required positional argument: 'dbpath'")
4140

@@ -61,14 +60,13 @@ def add_columns(self,
6160
database:str="",
6261
table:str=""):
6362
"""
64-
add columns to an existing table / define columns before creating a table
63+
Add columns to an existing table / define columns before creating a table.
6564
66-
if use for create new table: sqlite cannot create table without columns.
65+
If use for create new table: sqlite cannot create table without columns.
6766
so user must first define the columns and create a table.
6867
important: user have to close connection here. if not, code returns error.
6968
because it tries to add column to existing table.
7069
"""
71-
7270
# checks if the user is trying to add unsupported data type
7371
if datatype.upper() not in DATA_TYPES:
7472
raise TypeError("datatype not supported, '{}'".format(datatype))
@@ -81,7 +79,7 @@ def add_columns(self,
8179
# column to an existing table.
8280
self.create_connection(database=database)
8381
cursor = self.connection.cursor()
84-
sql_cmd = "ALTER TABLE {} ADD COLUMN {} {}".format(table, column_name, datatype)
82+
sql_cmd = "ALTER TABLE " + table + " ADD COLUMN " + column_name + " " + datatype
8583
if not_null:
8684
sql_cmd += " NOT NULL"
8785
if primary_key:
@@ -92,7 +90,7 @@ def add_columns(self,
9290
# if table is not defines, it means that the user is trying to add / define
9391
# a column to a new table. so the following code add SQL syntax globally for
9492
# use when creating new table
95-
self._add_columns_cmd += (",{} {}".format(column_name, datatype))
93+
self._add_columns_cmd += "," + column_name + " " + datatype
9694

9795
if primary_key:
9896
self._add_columns_cmd += " PRIMARY KEY"
@@ -103,7 +101,7 @@ def add_columns(self,
103101
return True
104102

105103
def create_table(self, table_name:str, database:str=""):
106-
"""creates new table in database"""
104+
"""Create new table in database."""
107105
if self.connection == "" and not database:
108106
raise TypeError("create_table() missing 1 required positional argument: 'database'")
109107

@@ -116,13 +114,13 @@ def create_table(self, table_name:str, database:str=""):
116114
if self._add_columns_cmd == "":
117115
raise NotImplementedError("call 'add_columns' function before create table")
118116

119-
sql_cmd = "CREATE TABLE {} ({})".format(table_name, self._add_columns_cmd[1:])
117+
sql_cmd = "CREATE TABLE " + table_name + " (" + self._add_columns_cmd[1:] + ")"
120118

121119
self.connection.execute(sql_cmd)
122120
return True
123121

124122
def all_tables(self, database:str=""):
125-
"""get a list of all the tables in the database"""
123+
"""Get a list of all the tables in the database."""
126124
if self.connection == "" and not database:
127125
raise TypeError("all_tables() missing 1 required positional argument: 'database'")
128126

@@ -134,7 +132,7 @@ def all_tables(self, database:str=""):
134132
return [tables[0] for tables in cursor.execute(sql_cmd)]
135133

136134
def is_table(self, table_name:str, database:str=""):
137-
"""checks if the given table is exists in the database"""
135+
"""Check if the given table is exists in the database."""
138136
if self.connection == "" and not database:
139137
raise TypeError("is_table() missing 1 required positional argument: 'database'")
140138

@@ -146,7 +144,7 @@ def is_table(self, table_name:str, database:str=""):
146144
return False
147145

148146
def delete_table(self, table:str, database:str=""):
149-
"""delete a table from the database"""
147+
"""Delete a table from the database."""
150148
if self.connection == "" and not database:
151149
raise TypeError("delete_table() missing 1 required positional argument: 'database'")
152150

@@ -155,7 +153,7 @@ def delete_table(self, table:str, database:str=""):
155153

156154
if self.is_table(table_name=table):
157155
cursor = self.connection.cursor()
158-
sql_cmd = "DROP TABLE {};".format(table)
156+
sql_cmd = "DROP TABLE " + table + ";"
159157
cursor.execute(sql_cmd)
160158

161159
return True
@@ -164,7 +162,7 @@ def delete_table(self, table:str, database:str=""):
164162
raise sqlite3.OperationalError("no such table: {}".format(table))
165163

166164
def get_all_column_types(self, table:str, database:str=""):
167-
"""get all the column names with the data types in a table"""
165+
"""Get all the column names with the data types in a table."""
168166
if self.connection == "" and not database:
169167
raise TypeError(
170168
"get_all_column_types() missing 1 required positional argument: 'database'")
@@ -175,7 +173,7 @@ def get_all_column_types(self, table:str, database:str=""):
175173
if self.is_table(table_name=table, database=database):
176174
cursor = self.connection.cursor()
177175

178-
sql_cmd = "PRAGMA TABLE_INFO({});".format(table)
176+
sql_cmd = "PRAGMA TABLE_INFO(" + table + ");"
179177
fetch = cursor.execute(sql_cmd)
180178

181179
data_dict = {}
@@ -188,7 +186,7 @@ def get_all_column_types(self, table:str, database:str=""):
188186
raise sqlite3.OperationalError("no such table: {}".format(table))
189187

190188
def get_column_type(self, table:str, column:str, database:str=""):
191-
"""get data type of a column in a table"""
189+
"""Get data type of a column in a table."""
192190
all_data = self.get_all_column_types(table=table, database=database)
193191

194192
# if columns exists in the table and given column in the table
@@ -198,7 +196,7 @@ def get_column_type(self, table:str, column:str, database:str=""):
198196
raise sqlite3.OperationalError("no such column: {}".format(column))
199197

200198
def get_columns(self, table:str, database:str=""):
201-
"""get all the column names list in a table"""
199+
"""Get all the column names list in a table."""
202200
if self.connection == "" and not database:
203201
raise TypeError("get_columns() missing 1 required positional argument: 'database'")
204202

@@ -215,7 +213,7 @@ def get_columns(self, table:str, database:str=""):
215213
return columns
216214

217215
def get_primary_key(self, table:str, database:str=""):
218-
"""find and get primary key of a table"""
216+
"""Find and get primary key of a table."""
219217
if self.connection == "" and not database:
220218
raise TypeError("get_primary_key() missing 1 required positional argument: 'database'")
221219

@@ -225,15 +223,15 @@ def get_primary_key(self, table:str, database:str=""):
225223
if self.is_table(table_name=table, database=database):
226224
cursor = self.connection.cursor()
227225

228-
sql_cmd = "SELECT * FROM pragma_table_info('{}') WHERE pk;".format(table)
229-
fetch = cursor.execute(sql_cmd)
226+
sql_cmd = "SELECT * FROM pragma_table_info(?) WHERE pk;"
227+
fetch = cursor.execute(sql_cmd, (table,))
230228
return fetch.fetchall()[0][1]
231229

232230
# raise OperationalError if the given table not exists
233231
raise sqlite3.OperationalError("no such table: {}".format(table))
234232

235233
def add_record(self, table:str, record, database:str=""):
236-
"""add a new record to a table"""
234+
"""Add a new record to a table."""
237235
if self.connection == "" and not database:
238236
raise TypeError("add_record() missing 1 required positional argument: 'database'")
239237

@@ -252,7 +250,7 @@ def add_record(self, table:str, record, database:str=""):
252250
all_columns[column] = ""
253251

254252
fields = []
255-
sql_cmd = "INSERT INTO {} VALUES(".format(table)
253+
sql_cmd = "INSERT INTO " + table + " VALUES("
256254

257255
# if record is dict type,..
258256
if isinstance(record, dict):
@@ -288,7 +286,7 @@ def add_record(self, table:str, record, database:str=""):
288286
raise sqlite3.OperationalError("no such table: {}".format(table))
289287

290288
def get_record(self, table:str, primary_key, database:str=""):
291-
"""get row data / record from a table using the primary key"""
289+
"""Get row data / record from a table using the primary key."""
292290
if self.connection == "" and not database:
293291
raise TypeError("get_record() missing 1 required positional argument: 'database'")
294292

@@ -298,8 +296,7 @@ def get_record(self, table:str, primary_key, database:str=""):
298296
if self.is_table(table_name=table, database=database):
299297
cursor = self.connection.cursor()
300298

301-
sql_cmd = "SELECT * FROM {} WHERE {}=?;".format(
302-
table, self.get_primary_key(table=table, database=database))
299+
sql_cmd = "SELECT * FROM " + table + " WHERE " + self.get_primary_key(table=table, database=database) + "=?;"
303300
fetch = cursor.execute(sql_cmd, (primary_key,))
304301

305302
# get columns list using get_columns
@@ -321,7 +318,7 @@ def get_record(self, table:str, primary_key, database:str=""):
321318
raise sqlite3.OperationalError("no such table: {}".format(table))
322319

323320
def get_all_records(self, table:str, database:str=""):
324-
"""get all data / records of a table"""
321+
"""Get all data / records of a table."""
325322
if self.connection == "" and not database:
326323
raise TypeError("get_all_records() missing 1 required positional argument: 'database'")
327324

@@ -331,7 +328,7 @@ def get_all_records(self, table:str, database:str=""):
331328
if self.is_table(table_name=table, database=database):
332329
cursor = self.connection.cursor()
333330

334-
sql_cmd = "SELECT * FROM {}".format(table)
331+
sql_cmd = "SELECT * FROM " + table
335332
cursor.execute(sql_cmd)
336333
rows = cursor.fetchall()
337334

@@ -353,7 +350,7 @@ def get_all_records(self, table:str, database:str=""):
353350
raise sqlite3.OperationalError("no such table: {}".format(table))
354351

355352
def delete_record(self, table:str, primary_key, database:str=""):
356-
"""delete record from a table"""
353+
"""Delete record from a table."""
357354
if self.connection == "" and not database:
358355
raise TypeError("delete_record() missing 1 required positional argument: 'database'")
359356

@@ -362,8 +359,7 @@ def delete_record(self, table:str, primary_key, database:str=""):
362359

363360
if self.is_table(table_name=table, database=database):
364361
cursor = self.connection.cursor()
365-
sql = "DELETE FROM {} WHERE {}=?".format(
366-
table, self.get_primary_key(table=table, database=database))
362+
sql = "DELETE FROM " + table + " WHERE " + self.get_primary_key(table=table, database=database) + "=?"
367363
cursor.execute(sql, (primary_key,))
368364
self.connection.commit()
369365

@@ -374,9 +370,9 @@ def delete_record(self, table:str, primary_key, database:str=""):
374370

375371
def filter_records(self, table:str, values:dict, database:str=""):
376372
"""
377-
get filtered record list from a table
373+
Get filtered record list from a table.
378374
379-
this will return one or more records by checking the values.
375+
This will return one or more records by checking the values.
380376
"""
381377
if self.connection == "" and not database:
382378
raise TypeError("filter_records() missing 1 required positional argument: 'database'")
@@ -389,7 +385,7 @@ def filter_records(self, table:str, values:dict, database:str=""):
389385

390386
operators = [">", "<", "!", "="]
391387

392-
sql = "SELECT * FROM {} WHERE ".format(table)
388+
sql = "SELECT * FROM " + table + " WHERE "
393389

394390
for value in values:
395391
try:
@@ -427,6 +423,6 @@ def filter_records(self, table:str, values:dict, database:str=""):
427423
raise sqlite3.OperationalError("no such table: {}".format(table))
428424

429425
def close_connection(self):
430-
"""close the connection with the SQLite database file"""
426+
"""Close the connection with the SQLite database file."""
431427
self.connection.close()
432428
return True

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setup(
99
name="ReallySimpleDB",
10-
version="1.1",
10+
version="1.2",
1111
description="A tool for easily manage databases with Python",
1212
long_description=long_description,
1313
long_description_content_type="text/markdown",

0 commit comments

Comments
 (0)