From 41b60ea45f3b4c36742e244d9c731db95c5281fc Mon Sep 17 00:00:00 2001 From: Moul <moul@moul.re> Date: Tue, 20 Jun 2023 21:09:25 +0200 Subject: [PATCH] Store authentication file with 600 permissions (#203) --- duniterpy/key/signing_key.py | 17 +++++++++++------ tests/key/test_signing_key.py | 7 +++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/duniterpy/key/signing_key.py b/duniterpy/key/signing_key.py index 4d33d19..f825164 100644 --- a/duniterpy/key/signing_key.py +++ b/duniterpy/key/signing_key.py @@ -14,6 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import base64 +import os import re from hashlib import scrypt, sha256 from pathlib import Path @@ -36,6 +37,10 @@ from .scrypt_params import ScryptParams SigningKeyType = TypeVar("SigningKeyType", bound="SigningKey") +def opener_user_rw(path, flags): + return os.open(path, flags, 0o600) + + class SigningKey(libnacl.sign.Signer): def __init__(self, seed: bytes) -> None: """ @@ -92,7 +97,7 @@ class SigningKey(libnacl.sign.Signer): :return: """ # capture credentials from file - with open(path, encoding="utf-8") as fh: + with open(path, encoding="utf-8", opener=opener_user_rw) as fh: lines = fh.readlines() assert len(lines) > 1 salt = lines[0].strip() @@ -107,7 +112,7 @@ class SigningKey(libnacl.sign.Signer): :param path: Authentication file path """ seedhex = convert_seed_to_seedhex(self.seed) - with open(path, "w", encoding="utf-8") as fh: + with open(path, "w", encoding="utf-8", opener=opener_user_rw) as fh: fh.write(seedhex) @staticmethod @@ -179,7 +184,7 @@ class SigningKey(libnacl.sign.Signer): :param path: Path to WIF file """ - with open(path, encoding="utf-8") as fh: + with open(path, encoding="utf-8", opener=opener_user_rw) as fh: pubsec_content = fh.read() # line patterns @@ -221,7 +226,7 @@ class SigningKey(libnacl.sign.Signer): Version: {version}\n\ pub: {self.pubkey}\n\ sec: {base58_signing_key}" - with open(path, "w", encoding="utf-8") as fh: + with open(path, "w", encoding="utf-8", opener=opener_user_rw) as fh: fh.write(content) @staticmethod @@ -341,7 +346,7 @@ sec: {base58_signing_key}" content = f"Type: WIF\n\ Version: {version}\n\ Data: {wif_key}" - with open(path, "w", encoding="utf-8") as fh: + with open(path, "w", encoding="utf-8", opener=opener_user_rw) as fh: fh.write(content) @staticmethod @@ -471,7 +476,7 @@ Data: {wif_key}" content = f"Type: EWIF\n\ Version: {version}\n\ Data: {ewif_key}" - with open(path, "w", encoding="utf-8") as fh: + with open(path, "w", encoding="utf-8", opener=opener_user_rw) as fh: fh.write(content) @classmethod diff --git a/tests/key/test_signing_key.py b/tests/key/test_signing_key.py index 26ee0fc..b2589b3 100644 --- a/tests/key/test_signing_key.py +++ b/tests/key/test_signing_key.py @@ -52,6 +52,13 @@ class TestSigningKey(unittest.TestCase): sign_key_load = SigningKey.from_seedhex_file(TEST_FILE_PATH) self.assertEqual(sign_key_save.sk, sign_key_load.sk) + def test_permissions_save_seedhex_file(self): + sign_key_save = SigningKey.from_credentials("alice", "password", ScryptParams()) + sign_key_save.save_seedhex_file(TEST_FILE_PATH) + + # https://www.geeksforgeeks.org/how-to-get-the-permission-mask-of-a-file-in-python/ + assert oct(os.stat(TEST_FILE_PATH).st_mode)[-3:] == "600" + def test_save_and_load_from_pubsec_file(self): sign_key_save = SigningKey.from_credentials("alice", "password", ScryptParams()) sign_key_save.save_pubsec_file(TEST_FILE_PATH) -- GitLab