diff --git a/docs/topics/Reference.adoc b/docs/topics/Reference.adoc index 9ea7e83c8..0440f0680 100644 --- a/docs/topics/Reference.adoc +++ b/docs/topics/Reference.adoc @@ -110,6 +110,7 @@ Use regular expressions to find and replace data from a resolved placeholder. Re |=== |Database Backup Path Placeholder |Description +|{CLIENT_HOSTNAME} |The hostname of the client performing the database save operation |{DB_FILENAME} |The database's filename without extension |{TIME} |The current time formatted as dd_MM_yyyy_hh-mm-ss. |{TIME:} |The current time formatted according to the format string specified by . See https://doc.qt.io/qt-5/qtime.html#toString for a list of available placeholders. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a5eb5d80..5df58f98d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -375,6 +375,7 @@ target_link_libraries(keepassxc_core ${qrcode_LIB} Qt5::Core Qt5::Concurrent + Qt5::Network ${BOTAN_LIBRARIES} ${PCSC_LIBRARIES} ${ZXCVBN_LIBRARIES} diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index 37a544c51..449e07c63 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -498,6 +499,10 @@ namespace Tools match = re.match(pattern); } + const QString hostName = QHostInfo::localHostName(); + + pattern.replace(QStringLiteral("{CLIENT_HOSTNAME}"), hostName); + // Replace escaped braces pattern.replace(QStringLiteral("\\{"), QStringLiteral("{")); pattern.replace(QStringLiteral("\\}"), QStringLiteral("}")); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 25b116d8e..27814e25b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -218,7 +218,7 @@ add_unit_test(NAME testdatabase SOURCES TestDatabase.cpp LIBS testsupport ${TEST_LIBRARIES}) add_unit_test(NAME testtools SOURCES TestTools.cpp - LIBS ${TEST_LIBRARIES}) + LIBS ${TEST_LIBRARIES} Qt5::Network) add_unit_test(NAME testconfig SOURCES TestConfig.cpp LIBS testsupport ${TEST_LIBRARIES}) diff --git a/tests/TestTools.cpp b/tests/TestTools.cpp index 3455e97c8..bfe79023f 100644 --- a/tests/TestTools.cpp +++ b/tests/TestTools.cpp @@ -21,6 +21,7 @@ #include "core/Tools.h" #include +#include #include #include #include @@ -132,6 +133,7 @@ void TestTools::testBackupFilePatternSubstitution_data() static const auto DEFAULT_DB_FILE_NAME = QStringLiteral("KeePassXC"); static const auto DEFAULT_DB_FILE_PATH = QStringLiteral("/tmp/") + DEFAULT_DB_FILE_NAME + QStringLiteral(".kdbx"); static const auto NOW = Clock::currentDateTime(); + static const QString TEST_CLIENT_HOSTNAME = QHostInfo::localHostName(); auto DEFAULT_FORMATTED_TIME = NOW.toString("dd_MM_yyyy_hh-mm-ss"); QTest::newRow("Null pattern") << QString() << DEFAULT_DB_FILE_PATH << QString(); @@ -140,13 +142,15 @@ void TestTools::testBackupFilePatternSubstitution_data() QTest::newRow("Empty database path") << "valid_pattern" << QString("") << QString(); QTest::newRow("Unclosed/invalid pattern") << "{DB_FILENAME" << DEFAULT_DB_FILE_PATH << "{DB_FILENAME"; QTest::newRow("Unknown pattern") << "{NO_MATCH}" << DEFAULT_DB_FILE_PATH << "{NO_MATCH}"; + QTest::newRow("Do not replace escaped patterns (client hostname)") + << "\\{CLIENT_HOSTNAME\\}" << DEFAULT_DB_FILE_PATH << "{CLIENT_HOSTNAME}"; QTest::newRow("Do not replace escaped patterns (filename)") << "\\{DB_FILENAME\\}" << DEFAULT_DB_FILE_PATH << "{DB_FILENAME}"; QTest::newRow("Do not replace escaped patterns (time)") << "\\{TIME:dd.MM.yyyy\\}" << DEFAULT_DB_FILE_PATH << "{TIME:dd.MM.yyyy}"; QTest::newRow("Multiple patterns should be replaced") - << "{DB_FILENAME} {TIME} {DB_FILENAME}" << DEFAULT_DB_FILE_PATH - << DEFAULT_DB_FILE_NAME + QStringLiteral(" ") + DEFAULT_FORMATTED_TIME + QStringLiteral(" ") + << "{CLIENT_HOSTNAME} {TIME} {DB_FILENAME}" << DEFAULT_DB_FILE_PATH + << TEST_CLIENT_HOSTNAME + QStringLiteral(" ") + DEFAULT_FORMATTED_TIME + QStringLiteral(" ") + DEFAULT_DB_FILE_NAME; QTest::newRow("Default time pattern") << "{TIME}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME; QTest::newRow("Default time pattern (empty formatter)") @@ -160,6 +164,9 @@ void TestTools::testBackupFilePatternSubstitution_data() + NOW.toString("yyyyMMdd_HHmmss") + QStringLiteral(".old.kdbx"); QTest::newRow("Invalid custom time pattern") << "{TIME:dd/-ss}" << DEFAULT_DB_FILE_PATH << NOW.toString("dd/-ss"); QTest::newRow("Recursive substitution") << "{TIME:'{TIME}'}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME; + QTest::newRow("{CLIENT_HOSTNAME} substitution") + << "some {CLIENT_HOSTNAME} thing" << DEFAULT_DB_FILE_PATH + << QStringLiteral("some ") + TEST_CLIENT_HOSTNAME + QStringLiteral(" thing"); QTest::newRow("{DB_FILENAME} substitution") << "some {DB_FILENAME} thing" << DEFAULT_DB_FILE_PATH << QStringLiteral("some ") + DEFAULT_DB_FILE_NAME + QStringLiteral(" thing");