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

Commit af51bc9

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 af51bc9

File tree

5 files changed

+60
-38
lines changed

5 files changed

+60
-38
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/client_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ def test_grant_admin_privileges(self):
688688

689689
self.assertEqual(
690690
m.last_request.qs['q'][0],
691-
'grant all privileges to test'
691+
'grant all privileges to "test"'
692692
)
693693

694694
@raises(Exception)
@@ -710,7 +710,7 @@ def test_revoke_admin_privileges(self):
710710

711711
self.assertEqual(
712712
m.last_request.qs['q'][0],
713-
'revoke all privileges from test'
713+
'revoke all privileges from "test"'
714714
)
715715

716716
@raises(Exception)
@@ -732,7 +732,7 @@ def test_grant_privilege(self):
732732

733733
self.assertEqual(
734734
m.last_request.qs['q'][0],
735-
'grant read on testdb to test'
735+
'grant read on "testdb" to "test"'
736736
)
737737

738738
@raises(Exception)
@@ -754,7 +754,7 @@ def test_revoke_privilege(self):
754754

755755
self.assertEqual(
756756
m.last_request.qs['q'][0],
757-
'revoke read on testdb from test'
757+
'revoke read on "testdb" from "test"'
758758
)
759759

760760
@raises(Exception)

influxdb/tests/server_tests/client_test_with_server.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,6 @@ def test_drop_user_nonexisting(self):
200200
self.assertIn('user not found',
201201
ctx.exception.content)
202202

203-
def test_drop_user_invalid(self):
204-
with self.assertRaises(InfluxDBClientError) as ctx:
205-
self.cli.drop_user('very invalid')
206-
self.assertEqual(400, ctx.exception.code)
207-
self.assertIn('{"error":"error parsing query: '
208-
'found invalid, expected',
209-
ctx.exception.content)
210-
211203
@unittest.skip("Broken as of 0.9.0")
212204
def test_revoke_admin_privileges(self):
213205
self.cli.create_user('test', 'test', admin=True)

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy