Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,10 @@
<source>Show autocomplete suggestions for username and additional attributes</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>URL Overrides</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ApplicationSettingsWidgetSecurity</name>
Expand Down Expand Up @@ -10669,6 +10673,51 @@ Example: JBSWY3DPEHPK3PXP</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>UrlOverrideWidget</name>
<message>
<source>Add</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remove</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Move Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Move Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>URL Scheme</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Command</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Confirm URL Scheme Overrides</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>You are about to change how KeePassXC opens URLs with certain schemes. Entries whose URL scheme matches one of these rules will run the configured command instead of the default action.

Do you want to save these changes?</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Run a command instead of opening URLs with a matching scheme. The first enabled match is used.&lt;br&gt;Commands must start with &lt;code&gt;cmd://&lt;/code&gt; and can use &lt;a href=&quot;https://keepassxc.org/docs/KeePassXC_UserGuide#_entry_placeholders&quot;&gt;Entry Placeholders&lt;/a&gt;.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>WelcomeWidget</name>
<message>
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ set(gui_SOURCES
gui/TotpExportSettingsDialog.cpp
gui/DatabaseOpenDialog.cpp
gui/URLEdit.cpp
gui/UrlOverride.cpp
gui/UrlOverrideWidget.cpp
gui/UrlTools.cpp
gui/WelcomeWidget.cpp
gui/csvImport/CsvImportWidget.cpp
Expand Down
4 changes: 3 additions & 1 deletion src/core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {

// Messages
{Config::Messages_NoLegacyKeyFileWarning, {QS("Messages/NoLegacyKeyFileWarning"), Roaming, false}},
{Config::Messages_HidePreReleaseWarning, {QS("Messages/HidePreReleaseWarning"), Local, {}}}};
{Config::Messages_HidePreReleaseWarning, {QS("Messages/HidePreReleaseWarning"), Local, {}}},

{Config::UrlOverride_Rules, {QS("UrlOverride/Rules"), Roaming, {}}}};

// clang-format on

Expand Down
2 changes: 2 additions & 0 deletions src/core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ class Config : public QObject
Messages_NoLegacyKeyFileWarning,
Messages_HidePreReleaseWarning,

UrlOverride_Rules,

// Special internal value
Deleted
};
Expand Down
4 changes: 4 additions & 0 deletions src/gui/ApplicationSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@ void ApplicationSettingsWidget::loadSettings()
hideWindowOnCopyCheckBoxToggled(m_generalUi->hideWindowOnCopyCheckBox->isChecked());
showExpiredEntriesOnDatabaseUnlockToggled(m_generalUi->showExpiredEntriesOnDatabaseUnlockCheckBox->isChecked());

m_generalUi->urlOverrideWidget->loadSettings();

for (const ExtraPage& page : asConst(m_extraPages)) {
page.loadSettings();
}
Expand Down Expand Up @@ -566,6 +568,8 @@ void ApplicationSettingsWidget::saveSettings()
config()->remove(Config::LastChallengeResponse);
}

m_generalUi->urlOverrideWidget->saveSettings();

// Save settings for additional pages
for (const ExtraPage& page : asConst(m_extraPages)) {
page.saveSettings();
Expand Down
27 changes: 27 additions & 0 deletions src/gui/ApplicationSettingsWidgetGeneral.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1580,11 +1580,38 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tabUrlOverrides">
<attribute name="title">
<string>URL Overrides</string>
</attribute>
<layout class="QVBoxLayout" name="urlOverridesLayout">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="UrlOverrideWidget" name="urlOverrideWidget" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>UrlOverrideWidget</class>
<extends>QWidget</extends>
<header>gui/UrlOverrideWidget.h</header>
</customwidget>
<customwidget>
<class>ShortcutWidget</class>
<extends>QLineEdit</extends>
Expand Down
15 changes: 11 additions & 4 deletions src/gui/DatabaseWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "gui/TotpDialog.h"
#include "gui/TotpExportSettingsDialog.h"
#include "gui/TotpSetupDialog.h"
#include "gui/UrlOverride.h"
#include "gui/dbsettings/DatabaseSettingsDialog.h"
#include "gui/entry/EntryView.h"
#include "gui/group/EditGroupWidget.h"
Expand Down Expand Up @@ -1001,15 +1002,21 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
return;
}

QString cmdString = entry->resolveMultiplePlaceholders(entry->url());
QString rawTemplate = entry->url();
const auto overrideCommand = UrlOverride::findCommand(rawTemplate);
if (!overrideCommand.isEmpty()) {
rawTemplate = overrideCommand;
}
QString cmdString = entry->resolveMultiplePlaceholders(rawTemplate);

if (cmdString.startsWith("cmd://")) {
// check if decision to execute command was stored
bool launch = (entry->attributes()->value(EntryAttributes::RememberCmdExecAttr) == "1");

// otherwise ask user
if (!launch && cmdString.length() > 6) {
QString cmdTruncated =
entry->resolveMultiplePlaceholders(EntryPlaceholders::maskPasswordPlaceholders(entry->url()));
entry->resolveMultiplePlaceholders(EntryPlaceholders::maskPasswordPlaceholders(rawTemplate));
cmdTruncated = cmdTruncated.mid(6);
if (cmdTruncated.length() > 400) {
cmdTruncated = cmdTruncated.left(400) + " […]";
Expand Down Expand Up @@ -1040,7 +1047,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
QStringList cmdList = QProcess::splitCommand(cmd);
if (!cmdList.isEmpty()) {
const QString program = cmdList.takeFirst();
QProcess::startDetached(program, cmdList);
UrlOverride::executeCommand(program, cmdList);
}

if (config()->get(Config::MinimizeOnOpenUrl).toBool()) {
Expand All @@ -1050,7 +1057,7 @@ void DatabaseWidget::openUrlForEntry(Entry* entry)
} else if (cmdString.startsWith("kdbx://")) {
openDatabaseFromEntry(entry, false);
} else {
QUrl url = QUrl::fromUserInput(entry->resolveMultiplePlaceholders(entry->url()));
QUrl url = QUrl::fromUserInput(cmdString);
if (!url.isEmpty()) {
#ifdef KEEPASSXC_DIST_APPIMAGE
QProcess::execute("xdg-open", {url.toString(QUrl::FullyEncoded)});
Expand Down
Loading