Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement recursive resolving for placeholders #1078

Conversation

frostasm
Copy link
Contributor

Implement recursive resolving for placeholders

Description

Recursive resolving for placeholders

From keepass help:

Referencing fields of other entries only works with standard fields, not with custom user strings. If you want to reference a custom user string, you need to place a redirection in a standard field of the entry with the custom string, using {S:}, and reference the standard field.

Currently KeePassXC does not support the described behavior.

Add support for {URL:Placeholders}

URL placeholders:

  • {URL:RMVSCM}
  • {URL:WITHOUTSCHEME} - analog for {URL:RMVSCM}
  • {URL:SCM}
  • {URL:SCHEME} - analog for {URL:SCM}
  • {URL:HOST}
  • {URL:PORT}
  • {URL:PATH}
  • {URL:QUERY}
  • {URL:FRAGMENT} - new url placeholder
  • {URL:USERINFO}
  • {URL:USERNAME}
  • {URL:PASSWORD}

Motivation and context

Implement behavior similar to keepass2

How has this been tested?

With unit test, TestEntry class.

Screenshots (if appropriate):

image

Types of changes

  • ✅ Bug fix (non-breaking change which fixes an issue)
  • ✅ New feature (non-breaking change which adds functionality)

Checklist:

  • ✅ I have read the CONTRIBUTING document. [REQUIRED]
  • ✅ My code follows the code style of this project. [REQUIRED]
  • ✅ All new and existing tests passed. [REQUIRED]
  • ✅ I have compiled and verified my code with -DWITH_ASAN=ON. [REQUIRED]
  • ✅ My change requires a change to the documentation.
  • ✅ I have added tests to cover my changes.

@frostasm
Copy link
Contributor Author

@droidmonkey @phoerious please review the changes

}

QString result = str;
QRegExp placeholderRegEx("(\\{.*\\})", Qt::CaseInsensitive, QRegExp::RegExp2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this regular expression. It matches zero-length placeholders and if greedy evaluation is used (it's not atm, but this may be a potential error source), it also matches placeholders containing closing braces and may produce unnecessary backtracking. You should change this to (\\{[^\\}]+).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


QString Entry::resolvePlaceholderRecursive(const QString &placeholder, int maxDepth) const
{
const PlaceholderType placeholderType = this->placeholderType(placeholder);
Copy link
Member

@phoerious phoerious Oct 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this pointer is not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is useful for debugging, have the value which is returned by the function in a separate variable. I renamed the local variable.

Copy link
Member

@phoerious phoerious Oct 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant the explicit this pointer is not needed. Just call placeholderType() without this->.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code didn't work, variable name overrides the function name

const PlaceholderType placeholderType = placeholderType(placeholder); 

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename the variable then.

const Entry* refEntry = m_group->database()->resolveEntry(referencedUuid);
if (refEntry) {
const QString wantedField = referenceRegExp->cap(wantedFieldIndex).toLower();
if (wantedField == "t") result = refEntry->title();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't put condition and body on the same line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use brackets on all conditional statements (styleguide).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

case PlaceholderType::UrlPassword:
return qurl.password();
default:
Q_ASSERT(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Q_ASSERT_X. Q_ASSERT(false) gives not useful error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


Entry::PlaceholderType Entry::placeholderType(const QString &placeholder) const
{
if (!placeholder.startsWith(QLatin1Char('{')) || !placeholder.endsWith(QLatin1Char('}'))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this case ever occur?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. In some places, the function "resolvePlaceholder" called directly.

{ QStringLiteral("{URL:PASSWORD}"), PlaceholderType::UrlPassword }
};

PlaceholderType result = placeholders.value(placeholder.toUpper(), PlaceholderType::Unknown);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable assignment is redundant. Directly return the result.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -158,3 +160,109 @@ void TestEntry::testResolveUrl()

delete entry;
}

void TestEntry::testResolveUrlPlaceholders()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for tests!


void TestEntry::testResolveUrlPlaceholders()
{
Entry* entry = new Entry();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use a stack variable here. No need for dynamic allocation. Or at least use a QScopedPointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


void TestEntry::testResolveRecursivePlaceholders()
{
Database* db = new Database();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@phoerious phoerious added this to the v2.3.0 milestone Oct 16, 2017
QString userinfo("user:pw"); // User information of the entry URL.
QString username("user"); // User name of the entry URL.
QString password("pw"); // Password of the entry URL.
QString fragment("fragment"); // Password of the entry URL.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here is wrong, just a typo :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@frostasm
Copy link
Contributor Author

I have one question. When I make changes to correct the observations. I must use squashing or I can just push new changes with a new commit?

@TheZ3ro
Copy link
Contributor

TheZ3ro commented Oct 16, 2017

IMHO it's the best if you make new commits so we can see the changes easily.

We will squash when merging if needed (most of the time we don't)

@frostasm
Copy link
Contributor Author

@TheZ3ro thanks for the explanation

@TheZ3ro
Copy link
Contributor

TheZ3ro commented Oct 16, 2017

thanks for your contributions 😉

@droidmonkey
Copy link
Member

To me if its minor change thats obvious i just amend and force push. Otherwise a new commit is preferred.

@frostasm frostasm force-pushed the implement-recursive-resolving-for-placeholders branch from d8fce34 to 3a0c965 Compare October 17, 2017 19:55
@frostasm
Copy link
Contributor Author

Oops, what is the minimum version of Qt should be supported?

@phoerious
Copy link
Member

Until now it has been 5.2, which is required to build with Trusty. If it makes sense, we can upgrade it, though.

@frostasm frostasm force-pushed the implement-recursive-resolving-for-placeholders branch from 3a0c965 to 727c533 Compare October 19, 2017 18:01
@frostasm
Copy link
Contributor Author

I removed the usage of Q_ENUM

Database db;
Group* root = db.rootGroup();

Entry* entry1 = new Entry();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You used a stack variable for the test above, you can do the same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phoerious can I not use stack variables? The database will still destroy all records.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean free store variables? Yes, you are right. I actually didn't mark it last time exactly for that reason. Forgot about it this time. All fine. Just rebase to current develop and I can merge this.

@frostasm frostasm force-pushed the implement-recursive-resolving-for-placeholders branch from 727c533 to f0fcc19 Compare October 19, 2017 19:41
@phoerious phoerious merged commit 190d3a1 into keepassxreboot:develop Oct 19, 2017
@frostasm
Copy link
Contributor Author

@phoerious @droidmonkey @TheZ3ro thanks guys ;)

@frostasm frostasm deleted the implement-recursive-resolving-for-placeholders branch October 19, 2017 20:36
phoerious added a commit that referenced this pull request Feb 27, 2018
- Add support for KDBX 4.0, Argon2 and ChaCha20 [#148, #1179, #1230, #1494]
- Add SSH Agent feature [#1098, #1450, #1463]
- Add preview panel with details of the selected entry [#879, #1338]
- Add more and configurable columns to entry table and allow copying of values by double click [#1305]
- Add KeePassXC-Browser API as a replacement for KeePassHTTP [#608]
- Deprecate KeePassHTTP [#1392]
- Add support for Steam one-time passwords [#1206]
- Add support for multiple Auto-Type sequences for a single entry [#1390]
- Adjust YubiKey HMAC-SHA1 challenge-response key generation for KDBX 4.0 [#1060]
- Replace qHttp with cURL for website icon downloads [#1460]
- Remove lock file [#1231]
- Add option to create backup file before saving [#1385]
- Ask to save a generated password before closing the entry password generator [#1499]
- Resolve placeholders recursively [#1078]
- Add Auto-Type button to the toolbar [#1056]
- Improve window focus handling for Auto-Type dialogs [#1204, #1490]
- Auto-Type dialog and password generator can now be exited with ESC [#1252, #1412]
- Add optional dark tray icon [#1154]
- Add new "Unsafe saving" option to work around saving problems with file sync services [#1385]
- Add IBus support to AppImage and additional image formats to Windows builds [#1534, #1537]
- Add diceware password generator to CLI [#1406]
- Add --key-file option to CLI [#816, #824]
- Add DBus interface for opening and closing KeePassXC databases [#283]
- Add KDBX compression options to database settings [#1419]
- Discourage use of old fixed-length key files in favor of arbitrary files [#1326, #1327]
- Correct reference resolution in entry fields [#1486]
- Fix window state and recent databases not being remembered on exit [#1453]
- Correct history item generation when configuring TOTP for an entry [#1446]
- Correct multiple TOTP bugs [#1414]
- Automatic saving after every change is now a default [#279]
- Allow creation of new entries during search [#1398]
- Correct menu issues on macOS [#1335]
- Allow compilation on OpenBSD [#1328]
- Improve entry attachments view [#1139, #1298]
- Fix auto lock for Gnome and Xfce [#910, #1249]
- Don't remember key files in file dialogs when the setting is disabled [#1188]
- Improve database merging and conflict resolution [#807, #1165]
- Fix macOS pasteboard issues [#1202]
- Improve startup times on some platforms [#1205]
- Hide the notes field by default [#1124]
- Toggle main window by clicking tray icon with the middle mouse button [#992]
- Fix custom icons not copied over when databases are merged [#1008]
- Allow use of DEL key to delete entries [#914]
- Correct intermittent crash due to stale history items [#1527]
- Sanitize newline characters in title, username and URL fields [#1502]
- Reopen previously opened databases in correct order [#774]
- Use system's zxcvbn library if available [#701]
- Implement various i18n improvements [#690, #875, #1436]
@phoerious phoerious added pr: new feature Pull request that adds a new feature and removed new feature labels Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: new feature Pull request that adds a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants