From 87d25de586f66797e699637b7cfa26d4415a2ab1 Mon Sep 17 00:00:00 2001 From: wolszewski Date: Thu, 24 Feb 2022 09:52:13 +0100 Subject: [PATCH] Add -a --atribute, -A --atribute-value, -P, --unprotect for managing attributes in cli for command add or edit --- docs/man/keepassxc-cli.1.adoc | 14 ++++++++++++ src/cli/Add.cpp | 34 +++++++++++++++++++++++++++++ src/cli/Add.h | 3 +++ src/cli/Edit.cpp | 40 ++++++++++++++++++++++++++++++++++- src/cli/Edit.h | 1 + 5 files changed, 91 insertions(+), 1 deletion(-) diff --git a/docs/man/keepassxc-cli.1.adoc b/docs/man/keepassxc-cli.1.adoc index b5eabd550..397b52500 100644 --- a/docs/man/keepassxc-cli.1.adoc +++ b/docs/man/keepassxc-cli.1.adoc @@ -195,6 +195,20 @@ The same password generation options as documented for the generate command can *--notes* <__notes__>:: Specifies the notes of the entry. +*-a*, *--attribute* <__attribute__>:: + Specifies the attribute of the entry. + +*-A*, *--attribute-value* <__attribute_value__>:: + Specifies value of the new attribute for the entry. + Value must be base64 encoded. + +*-P*, *--protect*:: + Protect value of the new attribute for the entry. + +*--unprotect*:: + Unprotect value of the attribute for the entry. + By default new attributes are not protected. + *-p*, *--password-prompt*:: Uses a password prompt for the entry's password. diff --git a/src/cli/Add.cpp b/src/cli/Add.cpp index 52785097b..1bbe5ad77 100644 --- a/src/cli/Add.cpp +++ b/src/cli/Add.cpp @@ -21,6 +21,7 @@ #include "Utils.h" #include "core/Group.h" #include "core/PasswordGenerator.h" +#include "core/Tools.h" #include @@ -44,6 +45,15 @@ const QCommandLineOption Add::GenerateOption = QCommandLineOption(QStringList() << "generate", QObject::tr("Generate a password for the entry.")); +const QCommandLineOption Add::AttributeOption = + QCommandLineOption(QStringList() << "a" << "attribute", QObject::tr("Name of the attribute for the entry."), QObject::tr("attribute")); + +const QCommandLineOption Add::AttributeValueOption = + QCommandLineOption(QStringList() << "A" << "attribute-value", QObject::tr("Value of the attribute for the entry."), QObject::tr("attribute-value")); + +const QCommandLineOption Add::AttributeProtectOption = + QCommandLineOption(QStringList() << "P" << "protect", QObject::tr("Set the attribute to be protected.")); + Add::Add() { name = QString("add"); @@ -52,6 +62,9 @@ Add::Add() options.append(Add::UrlOption); options.append(Add::NotesOption); options.append(Add::PasswordPromptOption); + options.append(Add::AttributeOption); + options.append(Add::AttributeValueOption); + options.append(Add::AttributeProtectOption); positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to add."), QString("")}); // Password generation options. @@ -120,6 +133,27 @@ int Add::executeWithDatabase(QSharedPointer database, QSharedPointersetPassword(password); } + if (!parser->value(Add::AttributeOption).isEmpty()) { + + bool attributeProtect = false; + if(parser->isSet(Add::AttributeProtectOption)) { + attributeProtect = true; + } + + QString attributeValue = ""; + if(parser->isSet(Add::AttributeValueOption)) { + QByteArray qbaAttributeValue = parser->value(Add::AttributeValueOption).toUtf8(); + if(!Tools::isBase64(qbaAttributeValue)){ + err << QObject::tr("Attribute value is not base64 encoded.") << endl; + return EXIT_FAILURE; + }else{ + attributeValue = QString( QByteArray::fromBase64(qbaAttributeValue) ); + } + } + + entry->attributes()->set(parser->value(Add::AttributeOption),attributeValue,attributeProtect); + } + QString errorMessage; if (!database->save(Database::Atomic, {}, &errorMessage)) { err << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl; diff --git a/src/cli/Add.h b/src/cli/Add.h index e36ec5eb3..569f682e0 100644 --- a/src/cli/Add.h +++ b/src/cli/Add.h @@ -31,6 +31,9 @@ public: static const QCommandLineOption UrlOption; static const QCommandLineOption NotesOption; static const QCommandLineOption PasswordPromptOption; + static const QCommandLineOption AttributeOption; + static const QCommandLineOption AttributeValueOption; + static const QCommandLineOption AttributeProtectOption; static const QCommandLineOption GenerateOption; }; diff --git a/src/cli/Edit.cpp b/src/cli/Edit.cpp index 3327d637a..04a5fc8f9 100644 --- a/src/cli/Edit.cpp +++ b/src/cli/Edit.cpp @@ -22,6 +22,7 @@ #include "Utils.h" #include "core/Group.h" #include "core/PasswordGenerator.h" +#include "core/Tools.h" #include @@ -29,6 +30,8 @@ const QCommandLineOption Edit::TitleOption = QCommandLineOption(QStringList() << << "title", QObject::tr("Title for the entry."), QObject::tr("title")); +const QCommandLineOption Edit::AttributeUnprotectOption = + QCommandLineOption(QStringList() << "unprotect", QObject::tr("Set the attribute to be not protected.")); Edit::Edit() { @@ -38,6 +41,10 @@ Edit::Edit() options.append(Add::UsernameOption); options.append(Add::UrlOption); options.append(Add::NotesOption); + options.append(Add::AttributeOption); + options.append(Add::AttributeValueOption); + options.append(Add::AttributeProtectOption); + options.append(Edit::AttributeUnprotectOption); options.append(Add::PasswordPromptOption); options.append(Edit::TitleOption); positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to edit."), QString("")}); @@ -90,11 +97,38 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< QString url = parser->value(Add::UrlOption); QString notes = parser->value(Add::NotesOption); QString title = parser->value(Edit::TitleOption); + QString attribute = parser->value(Add::AttributeOption); bool prompt = parser->isSet(Add::PasswordPromptOption); - if (username.isEmpty() && url.isEmpty() && notes.isEmpty() && title.isEmpty() && !prompt && !generate) { + if (username.isEmpty() && url.isEmpty() && notes.isEmpty() && title.isEmpty() && attribute.isEmpty() && !prompt && !generate) { err << QObject::tr("Not changing any field for entry %1.").arg(entryPath) << endl; return EXIT_FAILURE; } + bool attributeProtect = parser->isSet(Add::AttributeProtectOption); + bool attributeUnprotect = parser->isSet(Edit::AttributeUnprotectOption); + if (attributeProtect && attributeUnprotect){ + err << QObject::tr("Protect and unprotect flag cannot be used together.") << endl; + return EXIT_FAILURE; + } + + QString attributeValue = ""; + if (!attribute.isEmpty()) { + + if(!attributeProtect && !attributeUnprotect) { + attributeProtect = entry->attributes()->isProtected(attribute); + } + + if(parser->isSet(Add::AttributeValueOption)) { + QByteArray qbaAttributeValue = parser->value(Add::AttributeValueOption).toUtf8(); + if(!Tools::isBase64(qbaAttributeValue)){ + err << QObject::tr("Attribute value is not base64 encoded.") << endl; + return EXIT_FAILURE; + }else{ + attributeValue = QString( QByteArray::fromBase64(qbaAttributeValue) ); + } + }else{ + attributeValue = entry->attribute(attribute); + } + } entry->beginUpdate(); @@ -122,6 +156,10 @@ int Edit::executeWithDatabase(QSharedPointer database, QSharedPointer< QString password = passwordGenerator->generatePassword(); entry->setPassword(password); } + + if (!attribute.isEmpty()) { + entry->attributes()->set(attribute,attributeValue,attributeProtect); + } entry->endUpdate(); diff --git a/src/cli/Edit.h b/src/cli/Edit.h index 089a7d886..fe9481466 100644 --- a/src/cli/Edit.h +++ b/src/cli/Edit.h @@ -27,6 +27,7 @@ public: int executeWithDatabase(QSharedPointer db, QSharedPointer parser) override; static const QCommandLineOption TitleOption; + static const QCommandLineOption AttributeUnprotectOption; }; #endif // KEEPASSXC_EDIT_H