This commit is contained in:
Ryan Steed 2026-03-07 05:59:28 +01:00 committed by GitHub
commit d9cc6dd27b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 17 additions and 3 deletions

View file

@ -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:<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.

View file

@ -375,6 +375,7 @@ target_link_libraries(keepassxc_core
${qrcode_LIB}
Qt5::Core
Qt5::Concurrent
Qt5::Network
${BOTAN_LIBRARIES}
${PCSC_LIBRARIES}
${ZXCVBN_LIBRARIES}

View file

@ -32,6 +32,7 @@
#include <QElapsedTimer>
#include <QEventLoop>
#include <QFileInfo>
#include <QHostInfo>
#include <QIODevice>
#include <QLocale>
#include <QMetaProperty>
@ -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("}"));

View file

@ -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})

View file

@ -21,6 +21,7 @@
#include "core/Tools.h"
#include <QFileInfo>
#include <QHostInfo>
#include <QRegularExpression>
#include <QTest>
#include <QUuid>
@ -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");