From be32b9619bd08cad476f928b64d8041122a35d4e Mon Sep 17 00:00:00 2001 From: markspanbroek Date: Mon, 7 Nov 2022 09:54:24 -0500 Subject: [PATCH] Fixes loading of private key on Windows (#299) Unix permissions don't work on Windows; adds check for correct ACL settings in Windows. --- codex/utils/fileutils.nim | 6 ++++++ codex/utils/keyutils.nim | 4 ++-- tests/codex/testutils.nim | 1 + tests/codex/utils/testkeyutils.nim | 34 ++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/codex/utils/testkeyutils.nim diff --git a/codex/utils/fileutils.nim b/codex/utils/fileutils.nim index d96e646c..25ad6392 100644 --- a/codex/utils/fileutils.nim +++ b/codex/utils/fileutils.nim @@ -49,6 +49,12 @@ proc secureWriteFile*[T: byte|char](path: string, else: writeFile(path, data, 0o600) +proc checkSecureFile*(path: string): IOResult[bool] = + when defined(windows): + checkCurrentUserOnlyACL(path) + else: + ok (? getPermissionsSet(path) == {UserRead, UserWrite}) + proc checkAndCreateDataDir*(dataDir: string): bool = when defined(posix): let requiredPerms = 0o700 diff --git a/codex/utils/keyutils.nim b/codex/utils/keyutils.nim index 14d59bb2..2280da75 100644 --- a/codex/utils/keyutils.nim +++ b/codex/utils/keyutils.nim @@ -36,11 +36,11 @@ proc setupKey*(path: string): ?!PrivateKey = res = ? PrivateKey.random(Rng.instance()[]).mapFailure(CodexKeyError) bytes = ? res.getBytes().mapFailure(CodexKeyError) - ? path.writeFile(bytes, SafePermissions.toInt()).mapFailure(CodexKeyError) + ? path.secureWriteFile(bytes).mapFailure(CodexKeyError) return PrivateKey.init(bytes).mapFailure(CodexKeyError) info "Found a network private key" - if path.getPermissionsSet().get() != SafePermissions: + if not ? checkSecureFile(path).mapFailure(CodexKeyError): warn "The network private key file is not safe, aborting" return failure newException( CodexKeyUnsafeError, "The network private key file is not safe") diff --git a/tests/codex/testutils.nim b/tests/codex/testutils.nim index 6e75e15a..3b3b7c24 100644 --- a/tests/codex/testutils.nim +++ b/tests/codex/testutils.nim @@ -1,4 +1,5 @@ import ./utils/teststatemachine import ./utils/testoptionalcast +import ./utils/testkeyutils {.warning[UnusedImport]: off.} diff --git a/tests/codex/utils/testkeyutils.nim b/tests/codex/utils/testkeyutils.nim new file mode 100644 index 00000000..24b5f0ca --- /dev/null +++ b/tests/codex/utils/testkeyutils.nim @@ -0,0 +1,34 @@ +import std/unittest +import std/os +import pkg/libp2p +import pkg/questionable/results +import codex/utils/keyutils + +when defined(windows): + import stew/windows/acl + +suite "keyutils": + + let path = getTempDir() / "CodexTest" + + setup: + os.createDir(path) + + teardown: + os.removeDir(path) + + test "creates a key file when it does not exist yet": + check setupKey(path / "keyfile").isSuccess + check fileExists(path / "keyfile") + + test "stores key in a file that's only readable by the user": + discard !setupKey(path / "keyfile") + when defined(posix): + check getFilePermissions(path / "keyfile") == {fpUserRead, fpUserWrite} + when defined(windows): + check checkCurrentUserOnlyACL(path / "keyfile").get() + + test "reads key file when it does exist": + let key = !setupKey(path / "keyfile") + check !setupKey(path / "keyfile") == key +