Skip to content
This repository was archived by the owner on Oct 29, 2024. It is now read-only.

Commit b42075d

Browse files
committed
Properly quote all identifiers and literals in InfluxDBClient
Previously InfluxDBClient tried to quote some of the identifiers (database and usernames, etc), but a number of API calls didn't have any quoting, and the ones that had quoting didn't account for special characters inside the identifiers. Add new `quote_ident()` and `quote_literal()` functions to line_protocol.py and use them consistently in the client.
1 parent 7debaca commit b42075d

File tree

3 files changed

+56
-26
lines changed

3 files changed

+56
-26
lines changed

influxdb/client.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import requests.exceptions
1414
from sys import version_info
1515

16-
from influxdb.line_protocol import make_lines
16+
from influxdb.line_protocol import make_lines, quote_ident, quote_literal
1717
from influxdb.resultset import ResultSet
1818
from .exceptions import InfluxDBClientError
1919
from .exceptions import InfluxDBServerError
@@ -532,8 +532,8 @@ def alter_retention_policy(self, name, database=None,
532532
should be set. Otherwise the operation will fail.
533533
"""
534534
query_string = (
535-
"ALTER RETENTION POLICY \"{0}\" ON \"{1}\""
536-
).format(name, database or self._database)
535+
"ALTER RETENTION POLICY {0} ON {1}"
536+
).format(quote_ident(name), quote_ident(database or self._database))
537537
if duration:
538538
query_string += " DURATION {0}".format(duration)
539539
if replication:
@@ -553,8 +553,8 @@ def drop_retention_policy(self, name, database=None):
553553
:type database: str
554554
"""
555555
query_string = (
556-
"DROP RETENTION POLICY \"{0}\" ON \"{1}\""
557-
).format(name, database or self._database)
556+
"DROP RETENTION POLICY {0} ON {1}"
557+
).format(quote_ident(name), quote_ident(database or self._database))
558558
self.query(query_string)
559559

560560
def get_list_retention_policies(self, database=None):
@@ -611,8 +611,8 @@ def create_user(self, username, password, admin=False):
611611
privileges or not
612612
:type admin: boolean
613613
"""
614-
text = "CREATE USER \"{0}\" WITH PASSWORD '{1}'".format(username,
615-
password)
614+
text = "CREATE USER {0} WITH PASSWORD {1}".format(
615+
quote_ident(username), quote_literal(password))
616616
if admin:
617617
text += ' WITH ALL PRIVILEGES'
618618
self.query(text)
@@ -623,7 +623,7 @@ def drop_user(self, username):
623623
:param username: the username to drop
624624
:type username: str
625625
"""
626-
text = "DROP USER {0}".format(username)
626+
text = "DROP USER {0}".format(quote_ident(username))
627627
self.query(text)
628628

629629
def set_user_password(self, username, password):
@@ -634,7 +634,8 @@ def set_user_password(self, username, password):
634634
:param password: the new password for the user
635635
:type password: str
636636
"""
637-
text = "SET PASSWORD FOR {0} = '{1}'".format(username, password)
637+
text = "SET PASSWORD FOR {0} = {1}".format(
638+
quote_ident(username), quote_literal(password))
638639
self.query(text)
639640

640641
def delete_series(self, database=None, measurement=None, tags=None):
@@ -652,11 +653,12 @@ def delete_series(self, database=None, measurement=None, tags=None):
652653
database = database or self._database
653654
query_str = 'DROP SERIES'
654655
if measurement:
655-
query_str += ' FROM "{0}"'.format(measurement)
656+
query_str += ' FROM {0}'.format(quote_ident(measurement))
656657

657658
if tags:
658-
query_str += ' WHERE ' + ' and '.join(["{0}='{1}'".format(k, v)
659-
for k, v in tags.items()])
659+
tag_eq_list = ["{0}={1}".format(quote_ident(k), quote_literal(v))
660+
for k, v in tags.items()]
661+
query_str += ' WHERE ' + ' AND '.join(tag_eq_list)
660662
self.query(query_str, database=database)
661663

662664
def grant_admin_privileges(self, username):
@@ -668,7 +670,7 @@ def grant_admin_privileges(self, username):
668670
.. note:: Only a cluster administrator can create/drop databases
669671
and manage users.
670672
"""
671-
text = "GRANT ALL PRIVILEGES TO {0}".format(username)
673+
text = "GRANT ALL PRIVILEGES TO {0}".format(quote_ident(username))
672674
self.query(text)
673675

674676
def revoke_admin_privileges(self, username):
@@ -680,7 +682,7 @@ def revoke_admin_privileges(self, username):
680682
.. note:: Only a cluster administrator can create/ drop databases
681683
and manage users.
682684
"""
683-
text = "REVOKE ALL PRIVILEGES FROM {0}".format(username)
685+
text = "REVOKE ALL PRIVILEGES FROM {0}".format(quote_ident(username))
684686
self.query(text)
685687

686688
def grant_privilege(self, privilege, database, username):
@@ -695,8 +697,8 @@ def grant_privilege(self, privilege, database, username):
695697
:type username: str
696698
"""
697699
text = "GRANT {0} ON {1} TO {2}".format(privilege,
698-
database,
699-
username)
700+
quote_ident(database),
701+
quote_ident(username))
700702
self.query(text)
701703

702704
def revoke_privilege(self, privilege, database, username):
@@ -711,8 +713,8 @@ def revoke_privilege(self, privilege, database, username):
711713
:type username: str
712714
"""
713715
text = "REVOKE {0} ON {1} FROM {2}".format(privilege,
714-
database,
715-
username)
716+
quote_ident(database),
717+
quote_ident(username))
716718
self.query(text)
717719

718720
def get_list_privileges(self, username):
@@ -734,7 +736,7 @@ def get_list_privileges(self, username):
734736
{u'privilege': u'ALL PRIVILEGES', u'database': u'db2'},
735737
{u'privilege': u'NO PRIVILEGES', u'database': u'db3'}]
736738
"""
737-
text = "SHOW GRANTS FOR {0}".format(username)
739+
text = "SHOW GRANTS FOR {0}".format(quote_ident(username))
738740
return list(self.query(text).get_points())
739741

740742
def send_packet(self, packet):

influxdb/line_protocol.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,32 @@ def _escape_tag(tag):
5353
)
5454

5555

56+
def quote_ident(value):
57+
return "\"{0}\"".format(
58+
value.replace(
59+
"\\", "\\\\"
60+
).replace(
61+
"\"", "\\\""
62+
).replace(
63+
"\n", "\\n"
64+
)
65+
)
66+
67+
68+
def quote_literal(value):
69+
return "'{0}'".format(
70+
value.replace(
71+
"\\", "\\\\"
72+
).replace(
73+
"'", "\\'"
74+
)
75+
)
76+
77+
5678
def _escape_value(value):
5779
value = _get_unicode(value)
5880
if isinstance(value, text_type) and value != '':
59-
return "\"{0}\"".format(
60-
value.replace(
61-
"\"", "\\\""
62-
).replace(
63-
"\n", "\\n"
64-
)
65-
)
81+
return quote_ident(value)
6682
elif isinstance(value, integer_types) and not isinstance(value, bool):
6783
return str(value) + 'i'
6884
else:

influxdb/tests/test_line_protocol.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,15 @@ def test_make_lines_unicode(self):
7676
line_protocol.make_lines(data),
7777
'test,unicode_tag=\'Привет!\' unicode_val="Привет!"\n'
7878
)
79+
80+
def test_quote_ident(self):
81+
self.assertEqual(
82+
line_protocol.quote_ident(r"""\foo ' bar " Örf"""),
83+
r'''"\\foo ' bar \" Örf"'''
84+
)
85+
86+
def test_quote_literal(self):
87+
self.assertEqual(
88+
line_protocol.quote_literal(r"""\foo ' bar " Örf"""),
89+
r"""'\\foo \' bar " Örf'"""
90+
)

0 commit comments

Comments
 (0)