Skip to content

Commit 9af7c14

Browse files
feat: Add {CLIENT_HOSTNAME} placeholder support for backup file patterns
This commit introduces a new placeholder `{CLIENT_HOSTNAME}` that can be used in database backup file patterns. The hostname of the client performing the database save operation will be substituted in place of this placeholder. Changes include: - Documentation update to reference the new `{CLIENT_HOSTNAME}` placeholder in the Reference.adoc file - Implementation of hostname resolution using `QHostInfo::localHostName()` in Tools.cpp - Addition of Qt5::Network library dependency for both the autotype library and testtools unit test - New test cases to verify proper substitution of the `{CLIENT_HOSTNAME}` placeholder - Test case for escaped patterns to ensure they are not replaced - Updated existing test data to include CLIENT_HOSTNAME in multiple pattern replacement test The feature enhances backup file naming flexibility by allowing users to include the client hostname in their backup file names, which is particularly useful in multi-machine environments.
1 parent 72308a1 commit 9af7c14

File tree

5 files changed

+17
-3
lines changed

5 files changed

+17
-3
lines changed

docs/topics/Reference.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ Use regular expressions to find and replace data from a resolved placeholder. Re
110110
|===
111111
|Database Backup Path Placeholder |Description
112112

113+
|{CLIENT_HOSTNAME} |The hostname of the client performing the database save operation
113114
|{DB_FILENAME} |The database's filename without extension
114115
|{TIME} |The current time formatted as dd_MM_yyyy_hh-mm-ss.
115116
|{TIME:<format>} |The current time formatted according to the format string specified by <format>. See https://doc.qt.io/qt-5/qtime.html#toString for a list of available placeholders.

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ target_link_libraries(keepassxc_core
375375
${qrcode_LIB}
376376
Qt5::Core
377377
Qt5::Concurrent
378+
Qt5::Network
378379
${BOTAN_LIBRARIES}
379380
${PCSC_LIBRARIES}
380381
${ZXCVBN_LIBRARIES}

src/core/Tools.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <QElapsedTimer>
3333
#include <QEventLoop>
3434
#include <QFileInfo>
35+
#include <QHostInfo>
3536
#include <QIODevice>
3637
#include <QLocale>
3738
#include <QMetaProperty>
@@ -498,6 +499,10 @@ namespace Tools
498499
match = re.match(pattern);
499500
}
500501

502+
const QString hostName = QHostInfo::localHostName();
503+
504+
pattern.replace(QStringLiteral("{CLIENT_HOSTNAME}"), hostName);
505+
501506
// Replace escaped braces
502507
pattern.replace(QStringLiteral("\\{"), QStringLiteral("{"));
503508
pattern.replace(QStringLiteral("\\}"), QStringLiteral("}"));

tests/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ add_unit_test(NAME testdatabase SOURCES TestDatabase.cpp
218218
LIBS testsupport ${TEST_LIBRARIES})
219219

220220
add_unit_test(NAME testtools SOURCES TestTools.cpp
221-
LIBS ${TEST_LIBRARIES})
221+
LIBS ${TEST_LIBRARIES} Qt5::Network)
222222

223223
add_unit_test(NAME testconfig SOURCES TestConfig.cpp
224224
LIBS testsupport ${TEST_LIBRARIES})

tests/TestTools.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "core/Tools.h"
2222

2323
#include <QFileInfo>
24+
#include <QHostInfo>
2425
#include <QRegularExpression>
2526
#include <QTest>
2627
#include <QUuid>
@@ -132,6 +133,7 @@ void TestTools::testBackupFilePatternSubstitution_data()
132133
static const auto DEFAULT_DB_FILE_NAME = QStringLiteral("KeePassXC");
133134
static const auto DEFAULT_DB_FILE_PATH = QStringLiteral("/tmp/") + DEFAULT_DB_FILE_NAME + QStringLiteral(".kdbx");
134135
static const auto NOW = Clock::currentDateTime();
136+
static const QString TEST_CLIENT_HOSTNAME = QHostInfo::localHostName();
135137
auto DEFAULT_FORMATTED_TIME = NOW.toString("dd_MM_yyyy_hh-mm-ss");
136138

137139
QTest::newRow("Null pattern") << QString() << DEFAULT_DB_FILE_PATH << QString();
@@ -140,13 +142,15 @@ void TestTools::testBackupFilePatternSubstitution_data()
140142
QTest::newRow("Empty database path") << "valid_pattern" << QString("") << QString();
141143
QTest::newRow("Unclosed/invalid pattern") << "{DB_FILENAME" << DEFAULT_DB_FILE_PATH << "{DB_FILENAME";
142144
QTest::newRow("Unknown pattern") << "{NO_MATCH}" << DEFAULT_DB_FILE_PATH << "{NO_MATCH}";
145+
QTest::newRow("Do not replace escaped patterns (client hostname)")
146+
<< "\\{CLIENT_HOSTNAME\\}" << DEFAULT_DB_FILE_PATH << "{CLIENT_HOSTNAME}";
143147
QTest::newRow("Do not replace escaped patterns (filename)")
144148
<< "\\{DB_FILENAME\\}" << DEFAULT_DB_FILE_PATH << "{DB_FILENAME}";
145149
QTest::newRow("Do not replace escaped patterns (time)")
146150
<< "\\{TIME:dd.MM.yyyy\\}" << DEFAULT_DB_FILE_PATH << "{TIME:dd.MM.yyyy}";
147151
QTest::newRow("Multiple patterns should be replaced")
148-
<< "{DB_FILENAME} {TIME} {DB_FILENAME}" << DEFAULT_DB_FILE_PATH
149-
<< DEFAULT_DB_FILE_NAME + QStringLiteral(" ") + DEFAULT_FORMATTED_TIME + QStringLiteral(" ")
152+
<< "{CLIENT_HOSTNAME} {TIME} {DB_FILENAME}" << DEFAULT_DB_FILE_PATH
153+
<< TEST_CLIENT_HOSTNAME + QStringLiteral(" ") + DEFAULT_FORMATTED_TIME + QStringLiteral(" ")
150154
+ DEFAULT_DB_FILE_NAME;
151155
QTest::newRow("Default time pattern") << "{TIME}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME;
152156
QTest::newRow("Default time pattern (empty formatter)")
@@ -160,6 +164,9 @@ void TestTools::testBackupFilePatternSubstitution_data()
160164
+ NOW.toString("yyyyMMdd_HHmmss") + QStringLiteral(".old.kdbx");
161165
QTest::newRow("Invalid custom time pattern") << "{TIME:dd/-ss}" << DEFAULT_DB_FILE_PATH << NOW.toString("dd/-ss");
162166
QTest::newRow("Recursive substitution") << "{TIME:'{TIME}'}" << DEFAULT_DB_FILE_PATH << DEFAULT_FORMATTED_TIME;
167+
QTest::newRow("{CLIENT_HOSTNAME} substitution")
168+
<< "some {CLIENT_HOSTNAME} thing" << DEFAULT_DB_FILE_PATH
169+
<< QStringLiteral("some ") + TEST_CLIENT_HOSTNAME + QStringLiteral(" thing");
163170
QTest::newRow("{DB_FILENAME} substitution")
164171
<< "some {DB_FILENAME} thing" << DEFAULT_DB_FILE_PATH
165172
<< QStringLiteral("some ") + DEFAULT_DB_FILE_NAME + QStringLiteral(" thing");

0 commit comments

Comments
 (0)