Skip to content

Commit

Permalink
Fix bug when encrypting a file with chinese characters (#496)
Browse files Browse the repository at this point in the history
* Draft of the solution

* Nit change

* Add missing decrypt test

* Add UTF-8 encoding when writing an encrypted file
  • Loading branch information
Marinovsky authored Sep 5, 2024
1 parent 3b59b3d commit 2a477a3
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 6 deletions.
4 changes: 2 additions & 2 deletions lean/commands/decrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ def decrypt(project: Path,
source_files = project_manager.get_source_files(project)
try:
from lean.components.util.encryption_helper import get_decrypted_file_content_for_local_project
decrypted_data = get_decrypted_file_content_for_local_project(project,
decrypted_data = get_decrypted_file_content_for_local_project(project,
source_files, decryption_key, project_config_manager, organization_id)
except Exception as e:
raise RuntimeError(f"Could not decrypt project {project}: {e}")

for file, decrypted in zip(source_files, decrypted_data):
with open(file, 'w') as f:
with open(file, 'w', encoding="utf-8") as f:
f.write(decrypted)

# Mark the project as decrypted
Expand Down
2 changes: 1 addition & 1 deletion lean/commands/encrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def encrypt(project: Path,
except Exception as e:
raise RuntimeError(f"Could not encrypt project {project}: {e}")
for file, encrypted in zip(source_files, encrypted_data):
with open(file, 'w') as f:
with open(file, 'w', encoding="utf-8") as f:
f.write(encrypted)

# Mark the project as encrypted
Expand Down
4 changes: 2 additions & 2 deletions lean/components/util/encryption_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def get_decrypted_file_content_for_local_project(project: Path, source_files: Li
for file in source_files:
try:
# lets read and decrypt the file
with open(file, 'r') as f:
with open(file, 'r', encoding="utf-8") as f:
encrypted = f.read()
if not areProjectFilesAlreadyEncrypted:
decrypted = encrypted
Expand Down Expand Up @@ -131,7 +131,7 @@ def get_encrypted_file_content_for_local_project(project: Path, source_files: Li
for file in source_files:
try:
# lets read and decrypt the file
with open(file, 'r') as f:
with open(file, 'r', encoding= "utf-8") as f:
plain_text = f.read()
if areProjectFilesAlreadyEncrypted:
encrypted = plain_text
Expand Down
30 changes: 30 additions & 0 deletions tests/commands/test_decrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,36 @@ def test_decrypt_decrypts_file_in_case_project_not_in_decrypt_state() -> None:
assert project_config.get("encrypted", False) == False
assert project_config.get("encryption-key-path", None) == None

def test_decrypt_decrypts_file_that_has_a_chinese_character() -> None:
create_fake_lean_cli_directory()

project_path = Path.cwd() / "Python Project"

source_files = container.project_manager.get_source_files(project_path)
file_contents_map = {file.name: file.read_text() for file in source_files}

encryption_file_path = project_path / "encryption_x.txt"
encryption_file_path.write_text("是一的", encoding="utf-8")

result = CliRunner().invoke(lean, ["encrypt", "Python Project", "--key", encryption_file_path])

project_config = container.project_config_manager.get_project_config(project_path)
assert project_config.get("encrypted", False) != False
assert project_config.get("encryption-key-path", None) != None
for file in source_files:
assert file_contents_map[file.name] != file.read_text()

result = CliRunner().invoke(lean, ["decrypt", "Python Project", "--key", encryption_file_path])

assert result.exit_code == 0

source_files = container.project_manager.get_source_files(project_path)
for file in source_files:
assert file_contents_map[file.name] == file.read_text()
project_config = container.project_config_manager.get_project_config(project_path)
assert project_config.get("encrypted", False) == False
assert project_config.get("encryption-key-path", None) == None


def test_decrypt_does_not_change_file_in_case_project_already_in_decrypt_state() -> None:
create_fake_lean_cli_directory()
Expand Down
69 changes: 68 additions & 1 deletion tests/commands/test_encrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,30 @@ def test_encrypt_encrypts_file_in_case_project_not_in_encrypt_state() -> None:
assert project_config.get("encrypted", False) == True
assert project_config.get("encryption-key-path", None) == str(encryption_file_path)

def test_encrypt_encrypts_file_with_chinese_characters() -> None:
create_fake_lean_cli_directory()

project_path = Path.cwd() / "Python Project"

encryption_file_path = project_path / "encryption_x.txt"
encryption_file_path.write_text("是一的", encoding="utf-8")

project_config = container.project_config_manager.get_project_config(project_path)
assert project_config.get("encrypted", False) == False
assert project_config.get("encryption-key-path", None) == None

result = CliRunner().invoke(lean, ["encrypt", "Python Project", "--key", encryption_file_path])

assert result.exit_code == 0

source_files = container.project_manager.get_source_files(project_path)
expected_encrypted_files = _get_expected_encrypted_files_content()
for file in source_files:
assert expected_encrypted_files["chinese_" + file.name].strip() == file.read_text().strip()
project_config = container.project_config_manager.get_project_config(project_path)
assert project_config.get("encrypted", False) == True
assert project_config.get("encryption-key-path", None) == str(encryption_file_path)


def test_encrypt_does_not_change_file_in_case_project_already_in_encrypt_state() -> None:
create_fake_lean_cli_directory()
Expand Down Expand Up @@ -167,6 +191,23 @@ def _get_expected_encrypted_files_content() -> dict:
4T/vRU2aSdisuNMdXyuF4OH7ZgBdUYaNtfxmuJlmS4tYsom5xJfxrEEGG203gq0ME5eZCmu4JlLbEo1w
L4u74Hsr4mWkJKbMJMcwW8ByRuy/VJiWW8JKIcoB0yHlwLJ/YoqMDF0BPG5i2EF0DXu1USNC/vE="""
,
"chinese_main.py":
"""/hBXLMAwLMr3D0WTwS5lbHxJquOwtubD1rwNFPyrPkaFfn4oJF/MlHR0+ibh0S/HmOfZy3bSaNUNyVlv
GwUc6BkTVduHfl0m0doinxtovFkLMi33PWYwTrdr7tXWoklzq+J+AyjmaYiJsN9GxJvUzM3fsvRR7+5h
6j16o+zI/PHntLsldC2+66e3E1yP+b6uYrOaqubIs6ORGV3G9oViLfKCADiHTRLH+7885cJxN1Is1wOE
5zIIe4DOBnq92XpazPM/1Lk3ECcu/bno2capvjRtqXZiINv7QGGtcHyZ5C4vanfE9KkUbXTaDBtxrxSH
jmI/kNo+2DFM9BQ9YWK8bBYBUEt6cBDnyM6yBC33QCoYVOm37p3lj5mZkeePPSMdLmXfi7tZ7iySuT49
/iWJ88rddbKVKU2qMtGjem5loKTOtKWoqd2R/fpOLAr+rH2D/Zz/hwomD+TdQ3DyWSYES3B9mMhk2Mpk
jtWkTiMMRdOalmC6GyihFbvYVUU19MZr3nTk6aEjRs1lSOZ+HiNV3KcrOY5ZlgLazXWfa9BUPdbXiDNk
m7LoCb2deL+y+cvL92xuu9Vuu3coKPxpVR3wodrJHLvWma22QagNR1wVb3f7agBypJm0/Yjr4+bSfRK0
tNsmCtsMpGmlsFMYae0gl6IVR5VMTohetSf2/Fu2YsSpeBfAp3AN2vM3lfJtrC3WqVhWG+rnNa4ye5N0
OLELdewYwHyeHOq6UQKJ7Bx7andRhogpVp0SeQGtu2y44/PfnaWQXB2z6I4oRipqmwSHLDyvC9sZX4jq
d9zLWdJ3RrpeER0hC9XG1fa3WXG2sVJfjEyd54MFMO5/sgQhU+lbvDlXs2HkIx/bbNUz4yuaE4PD5xcO
9votaJDw3m4zFVBww8m+PO3ddHUUC672lP0jCZcsjYw2WlZNt5bC5DSvvzCVvDzIF5dc3IKKXpeWwadN
fLxzbUCRumfDes0yuw9E+nPKhbLCatXIGlp8c/wpQ+XyWD/SVI/vCJjHAzbYPY7nIVYp0FAnCQ6kpBbI
wb/6GovuiB5bl/zHc5iWw17zy+F//CjAv2RJUgEd4uiQWIOKohSd6yjUWbsvybIyGF+/DLs7F/ZbQqTi
qxP8h0s0CxgTowyBYncfYLOmD2AybNVQUPIE5DNIANKV2xWPTQo8NqZ/oDYFlaobqazmViTfrgM="""
,
"research.ipynb":
"""NIiAgzU8gzaJ3YEIWysBh0e0xxm9rpAWDE4Pir/wzKtla/wcbs98GU5cdOxgd7Gjlcu0zNbFzE5x8Eyx
qSuh3cQU17xQSisPxvjfDD/h2z9AnFT1jD1Vhc+Nn5ngwpgCA6P5fHT4VhPgaKDp7r9zc8pAURcSd04M
Expand All @@ -192,5 +233,31 @@ def _get_expected_encrypted_files_content() -> dict:
HrFPt9ElvzsATZvrloOCorTqbWc5BYmXb+u4MZ4vLtnU2wq/j5B+DvSswQkXsvtlGDsNPwLyi4dZuIVV
Oae0ese2fAU8lmosUY95ghYxEOGrMHg5ZPklje/afjpxwKAAgTfWqozYPdpNL+MJEqrVA9YRq5wSvjuX
UGw0ehtO8qY5FmPGcUlkBGuqmd7r6aLE4mosoZrc/UyZb+clWNYJITRLFJbQpWm3EU/Xrt5UM8uWwEdV
bFWAAkX56MyDHwJefC1nkA=="""
bFWAAkX56MyDHwJefC1nkA==""",
"chinese_research.ipynb":
"""YujNshgrEbvBBeZs6Dod4uQhoSpPAQRn31qHGUcoacZbmpPpm9XoTKOCz9/v3zcFkD/xNP88Ry/Q7Zra
X1k6SjoQsswUB4MM0i4HwieZCug7dKjarlO3OAN/RrMeH2x7DvJQsjDNKMlE1JdLQ2gZXcolLWRoQCsO
TFb/wXx5VhU9XGF756OTKDQmweIkLS8RNHhXgiC0eMwYlPafDz+EA5DDe9p6Vx+xb1wHs7UP+Hhz/ikj
8rL4JWrCRJVbCX0riZE9omwPnAAO2M5kyVNwArMc+H7PIE7zKJqhGwSzt+uXvOCv/3fHazbTEwHErhKK
padpAPsRsJVlgfgm8epD9KywctYvtHpmN1io47yXM4yhWQsLduBqSig4W/rPd54OYPL1af6v+mUhFWdm
XV4mQzO+crVCmEvyKIw85Ai1uXzOs2r10UNS5e+reD+jRz9pg9ZSzUY0wyTfvdL1FG9PJSmsK2uLnC2x
WNfjKW0sbmIOYy2gm8oz0cEOSE303KB//p5Tl57zorzPp2UTNPJZFW9YKD0NGglWKPCtJYDsLNX9gJu5
5Z7+a/S3GeizpV7VbvsoKZw7xYxLbKCfW2eJzgiaDE3XKMyXm6ohS+zZUC+5C1/Fidx2GyzMViDfF+sg
0dmwlxShkESdVHa8AigMkcJ1lIjeTiiBnqU6ujqe9t/HnderOfit2ZLUjEW06ogA32WVzsNXQfpiF1My
fPY92a/uv0Z7hW0FyaJeKC0PhVCfcXWIqjZ3vRx3otDgYGn+fy/Y6dcHZ8gsIMwG0Amd1bxU2hssxXqR
sUiTaZYetwQzoy8qci2hxo7GTdndELWChmZ6IpbdvnLdnMVHfDBE14n7IhrShtk02R9is/hn0BbwK2Hu
UvrYZowKcXKdHcofPR413ak9xlvgNwlyquy4q2NWdYlfxb2vN9QorhhSd5GKyhksbVOTfeklUdRCOza6
neXoiR2e8rv0BNnaBa4vnAhNxB+vp9MeTGFMqfvCRw7HuRT3+wJHwgtP1qjVK7n2jUF1dmAj6Bnxl7ju
Y0AEUsh+ioGjv1Jwn5WKEYuCFNN1YrttCabJP6JI+yjbzf6n6O6Ex10Zmea3rpxLAZ8Jpqm/A0b27XpT
FNEfo86uR5WO5yCmeUAtUCanknoXh41wmA762eJPMXubqlGQGijde3ZSaaSoxHaeCrfxhd63hqxxd8Uf
c7BA4yFmNpn9N9ZRwaSYDqsLmqbdvxhyBJQd3bu1aIMPX2NcxpGV87kjbfNRQCmdvj+H1/n+pFm/4MgU
xEndzUvoSQvRjIeU4eB2R5Um4j/beLMFxd6Is6ku2B3ypYqg9cqcaDuGbXzZ6mxLnpoVCPFCvDsRWJ8c
blGlOV0YfbzUDYlTFWxO/cs3hVOSpjhOVANOAtfQFt9ZLa00B8t1tRCNvjM7EX0nHf41T69c4V7ex+OJ
/5XNCwuWoHZ2GJSni3bxjZ3ZxhGhCkIvxIgGrUTmt1wGOKGKwjl88uD5bDWX4+sjom2oDGqQTvkIlZJn
kKiRBRvuG4VAv0QAv73+QURV0RGxMgedEjIFd8R9Yf2mb7IENzgq2SQSL065qWzoCRTBF+jVOP8fXdzs
KL21W4y756fM3nKMkFGQZbjPeHO5ojDjT/U3mMimgC/3haZy5mmLde9NJFHWM8SuEoA/0bnCgZV++vpZ
kqzmoRw8H4RE+oBT8W+ch6CZvEYYsTuAXIPe1cQBcNxanqk4Uh8gwlEko/zfffPS7r1FR3+pe0AajG+o
wT72mv1dhrRifrr0MVEZe1iRUdPwEjBttJjCr5bnnbmswSKf2fEg0cHRBv25z9t33mj4kth/T2W5zkw3
Zbni33aJFF6uM9VECyU1QlEz5Eu8lhecWs5ZxFtjT73K/5tqmcwNYx7sO1UpT3QPF1DQ7RlP1yTTkTw2
s0ntvYgXO0YOeItR43fpHw=="""
}

0 comments on commit 2a477a3

Please sign in to comment.