Skip to content

Commit 53ff7dd

Browse files
authored
Strip quotes from config entries (#7)
1 parent 0c07b62 commit 53ff7dd

File tree

9 files changed

+95
-10
lines changed

9 files changed

+95
-10
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.egg-info
2+
*.pyc

.travis.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ python:
44
- 3.4
55
- 3.5
66
- 3.6
7-
- 3.7-dev
7+
- 3.7
8+
- 3.8
9+
- 3.9
810

11+
before_install:
12+
- python --version
13+
- pip install -U pip
14+
- pip install -U pytest
915
install:
10-
- pip install cryptography
11-
16+
- pip install ".[test]" . # install package + test dependencies
1217
script:
13-
- MYSQL_TEST_LOGIN_FILE=`pwd`/test.mylogin.cnf python myloginpath.py
18+
- pytest

myloginpath.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ def parse(login_path: str, path=None) -> dict:
3636
)
3737
parser.read_string(read(path), source=path)
3838
data = dict(parser.items(login_path))
39-
if 'port' in data:
40-
data['port'] = int(data['port'])
39+
data = {key: _strip_quotes(value) for key, value in data.items()}
40+
if "port" in data:
41+
data["port"] = int(data["port"])
4142
return data
4243

4344

@@ -92,7 +93,7 @@ def _read_encrypted_file(f) -> bytes:
9293
length_buffer = f.read(_CIPHER_STORE_LENGTH)
9394
if len(length_buffer) < _CIPHER_STORE_LENGTH:
9495
break
95-
line_length, = struct.unpack("<i", length_buffer)
96+
(line_length,) = struct.unpack("<i", length_buffer)
9697
line = _read_line(f, line_length, decryptor)
9798
plaintext += line
9899

@@ -121,6 +122,17 @@ def _remove_pad(line):
121122
return line[:-pad_length]
122123

123124

125+
def _strip_quotes(value):
126+
"""If a value is quoted, remove the quotes at the beginning and end, then
127+
un-escape any quote characters inside the string."""
128+
if value.startswith('"') and value.endswith('"'):
129+
# This is a quoted string. Remove the first and
130+
# last quote, then unescape interior quotes.
131+
value = value[1:-1]
132+
value = value.replace('\\"', '"')
133+
return value
134+
135+
124136
if __name__ == "__main__":
125137
print(read())
126138
print(parse("test"))

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from setuptools import setup
2-
import pathlib
32

4-
readme = pathlib.Path("README.md").read_text("utf-8")
3+
with open("README.md", "rt") as f:
4+
readme = f.read()
55

66
setup(
77
name="myloginpath",
@@ -13,6 +13,6 @@
1313
url="https://github.com/PyMySQL/myloginpath/",
1414
keywords="MySQL",
1515
install_requires=["cryptography"],
16-
python_requires='>=3.4',
16+
python_requires=">=3.4",
1717
py_modules=["myloginpath"],
1818
)
File renamed without changes.

test/test_decrypt.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
""" Read each test vector, decrypt, and check that they're correct."""
2+
import myloginpath
3+
4+
5+
def test_normal():
6+
expected = """[test]
7+
user = testuser
8+
password = testpass
9+
host = testhost
10+
socket = testsocket
11+
port = 1234
12+
"""
13+
actual = myloginpath.read("test/test.mylogin.cnf")
14+
assert expected == actual
15+
16+
17+
def test_quoted():
18+
expected = """[test]
19+
user = "testuser"
20+
password = "testpass"
21+
host = "testhost"
22+
socket = "testsocket"
23+
port = 1234
24+
"""
25+
actual = myloginpath.read("test/test_quoted.mylogin.cnf")
26+
assert expected == actual
27+
28+
29+
def test_special():
30+
expected = """[test]
31+
host = "host with \\" quote"
32+
"""
33+
actual = myloginpath.read("test/test_special.mylogin.cnf")
34+
assert expected == actual

test/test_parse.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
""" Parse each test vector, and compare them to known-good values. """
2+
import myloginpath
3+
4+
5+
def test_normal():
6+
expected = {
7+
"host": "testhost",
8+
"password": "testpass",
9+
"port": 1234,
10+
"socket": "testsocket",
11+
"user": "testuser",
12+
}
13+
actual = myloginpath.parse("test", "test/test.mylogin.cnf")
14+
assert expected == actual
15+
16+
17+
def test_quoted():
18+
expected = {
19+
"host": "testhost",
20+
"password": "testpass",
21+
"port": 1234,
22+
"socket": "testsocket",
23+
"user": "testuser",
24+
}
25+
actual = myloginpath.parse("test", "test/test_quoted.mylogin.cnf")
26+
assert expected == actual
27+
28+
29+
def test_special():
30+
expected = {"host": 'host with " quote'}
31+
actual = myloginpath.parse("test", "test/test_special.mylogin.cnf")
32+
assert expected == actual

test/test_quoted.mylogin.cnf

208 Bytes
Binary file not shown.

test/test_special.mylogin.cnf

80 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)