commit 47e78be7e9111142f51fb1c106e04ab8583f5a7a Author: SET Date: Fri Oct 25 20:16:43 2019 +0200 Initial commit diff --git a/.dep.inc b/.dep.inc new file mode 100644 index 0000000..38ba445 --- /dev/null +++ b/.dep.inc @@ -0,0 +1,5 @@ +# This code depends on make tool being used +DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES} ${TESTOBJECTFILES})) +ifneq (${DEPFILES},) +include ${DEPFILES} +endif diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c0f64a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/ +build/ diff --git a/AppConfig.cpp b/AppConfig.cpp new file mode 100644 index 0000000..690b4c3 --- /dev/null +++ b/AppConfig.cpp @@ -0,0 +1,147 @@ +/* + * File: AppConfig.cpp + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 9 octobre 2019, 20:23 + */ + +#include "AppConfig.h" +#include "global.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// Hard coded. File must be in WT_APP_ROOT +#define JSON_CONFIG_FILE "k7config.json" +/* + { + "sCommonName" : { + "UserCommonName1" : { + "canImport" : true, + "canDelete" : true, + "privKeyIds" : [ + "fullKeyId1", + "fullKeyId2" + ] + }, + "UserCommonName2" : { + ... + } + } +} + */ + +AppConfig::AppConfig(WText * notifyWidget) +{ + m_notifyWidget = notifyWidget; +} + +AppConfig::~AppConfig() +{ +} + +bool AppConfig::LoadConfig() +{ + // Read config file + ifstream jsonFile; + const WString f(WApplication::appRoot() + WString(JSON_CONFIG_FILE)); + jsonFile.open(f.toUTF8().c_str()); + if (!jsonFile.is_open()) + { + m_notifyWidget->setText(TR("CantLoadConfig")); + return false; + } + string line; + WString configData; + while (getline(jsonFile, line)) + { + configData += WString(line); + } + jsonFile.close(); + + Json::ParseError pe; + Json::parse(configData.toUTF8(), m_RootObject, pe, false); + if (!string(pe.what()).empty()) + { + // pe.what() dumps all Json data + m_notifyWidget->setText(TR("CantParseJson")); + } + + if (!m_RootObject.contains("sCommonName")) + { + m_notifyWidget->setText(TR("CNObjectMissing")); + return false; + } + m_SubjectCNObject = m_RootObject.get("sCommonName"); + // If the client cert's subject common name is not listed, deny access. + const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); + if (!m_SubjectCNObject.contains(commonName.toUTF8())) + { + m_notifyWidget->setText(TR("AccessDenied")); + return false; + } + return true; +} + +bool AppConfig::CanImport() const +{ + const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); + if (!m_SubjectCNObject.contains(commonName.toUTF8())) // Should not happen, see above + return false; + Json::Object cnObject = m_SubjectCNObject.get(commonName.toUTF8()); + if (!cnObject.contains("canImport")) + return false; + return cnObject.get("canImport"); +} + +bool AppConfig::CanDelete() const +{ + const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); + if (!m_SubjectCNObject.contains(commonName.toUTF8())) + return false; + Json::Object cnObject = m_SubjectCNObject.get(commonName.toUTF8()); + if (!cnObject.contains("canDelete")) + return false; + return cnObject.get("canDelete"); +} + +vector AppConfig::PrivateKeyIds() const +{ + // List private key identifiers. + vector pKeyIds; + const WString commonName = GetSubjectDnAttribute(WSslCertificate::DnAttributeName::CommonName); + if (!m_SubjectCNObject.contains(commonName.toUTF8())) + return pKeyIds; + Json::Object cnObject = m_SubjectCNObject.get(commonName.toUTF8()); + if (!cnObject.contains("privKeyIds")) + return pKeyIds; + Json::Array aKeyId = cnObject.get("privKeyIds"); + for (uint i = 0; i < aKeyId.size(); i++) + { + pKeyIds.push_back(aKeyId.at(i)); + } + return pKeyIds; +} + +const WString AppConfig::GetSubjectDnAttribute(const WSslCertificate::DnAttributeName& attrName) const +{ + // Get an X509 client certificate attribute value + const vector * dnAttr + = &(WApplication::instance()->environment().sslInfo()->clientCertificate().subjectDn()); + for (uint i = 0; i < dnAttr->size(); i++) + { + if (dnAttr->at(i).name() == attrName) + return dnAttr->at(i).value(); + } + return WString::Empty; +} \ No newline at end of file diff --git a/AppConfig.h b/AppConfig.h new file mode 100644 index 0000000..cd8c516 --- /dev/null +++ b/AppConfig.h @@ -0,0 +1,73 @@ +/* + * File: AppConfig.h + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 9 octobre 2019, 20:23 + */ + +#ifndef APPCONFIG_H +#define APPCONFIG_H + +#include +#include +#include +#include +#include + +using namespace Wt; +using namespace std; + +/** + * Json configuration file reader. + */ +class AppConfig { +public: + AppConfig(WText * notifyWidget); + virtual ~AppConfig(); + /** + * Must be called by app. No autoloading of config file. + * @return + */ + bool LoadConfig(); + /** + * Can the user import keys ? + * @return + */ + bool CanImport() const; + /** + * Can the user delete keys ? N.B. : he may delete private keys + * only if he manages these keys. + * @return + */ + bool CanDelete() const; + /** + * List of full private key identifiers. The user may delete these private keys. + * Must be full keyid, short keyid or fingerprint. + * @return + */ + vector PrivateKeyIds() const; +private: + /** + * To display error messages + */ + WText * m_notifyWidget; + /** + * Root object of the config file + */ + Json::Object m_RootObject; + /** + * User object, identified by the Subject Common Name of the X509 client certificate. + */ + Json::Object m_SubjectCNObject; + /** + * Get an X509 client certificate attribute value + * @param attrName + * @return + */ + const WString GetSubjectDnAttribute(const WSslCertificate::DnAttributeName& attrName) const; +}; + +#endif /* APPCONFIG_H */ + diff --git a/GpgMECWorker.cpp b/GpgMECWorker.cpp new file mode 100644 index 0000000..daa86ee --- /dev/null +++ b/GpgMECWorker.cpp @@ -0,0 +1,34 @@ +/* + * File: GpgMECWorker.cpp + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 14 octobre 2019, 15:22 + */ + +#include "GpgMECWorker.h" + +GpgMECWorker::GpgMECWorker() { + gpgme_error_t c_err = gpgme_new(&c_ctx); +} + +GpgMECWorker::~GpgMECWorker() { + gpgme_release(c_ctx); +} + +bool GpgMECWorker::DeleteKey(const char * fullKeyId, bool secret, GpgME::Error& e) { + gpgme_key_t c_key; + gpgme_error_t c_err = gpgme_get_key(c_ctx, fullKeyId, &c_key, secret); + if (c_key == NULL) { + e = GpgME::Error::fromCode(c_err); + return false; + } + int flags = secret ? GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE : GPGME_DELETE_FORCE; + c_err = gpgme_op_delete_ext(c_ctx, c_key, flags); + if (c_err != 0) { + e = GpgME::Error::fromCode(c_err); + return false; + } + return true; +} \ No newline at end of file diff --git a/GpgMECWorker.h b/GpgMECWorker.h new file mode 100644 index 0000000..5f337e2 --- /dev/null +++ b/GpgMECWorker.h @@ -0,0 +1,38 @@ +/* + * File: GpgMECWorker.h + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 14 octobre 2019, 15:22 + */ + +#ifndef GPGMECWORKER_H +#define GPGMECWORKER_H + +#include +#include + +class GpgMECWorker { +public: + GpgMECWorker(); + virtual ~GpgMECWorker(); + + /** + * Deleting keys must be done with the C API because + * gpgmepp does not provide a way to use GPGME_DELETE_FORCE, + * resulting in a confirmation dialog triggered by GPG. + * This does not fit use on a web werver. + * @param fullKeyId + * @param secret delete secret key ? + * @param e + * @return + */ + bool DeleteKey(const char * fullKeyId, bool secret, GpgME::Error& e); + +private: + gpgme_ctx_t c_ctx; +}; + +#endif /* GPGMECWORKER_H */ + diff --git a/GpgMEWorker.cpp b/GpgMEWorker.cpp new file mode 100644 index 0000000..943ba26 --- /dev/null +++ b/GpgMEWorker.cpp @@ -0,0 +1,80 @@ +/* + * File: GpgMEWorker.cpp + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 11 octobre 2019, 16:34 + */ + +#include "GpgMEWorker.h" +#include +#include +#include +#include +#include + +GpgMEWorker::GpgMEWorker() +{ + m_ctx = Context::createForProtocol(Protocol::OpenPGP); +} + +GpgMEWorker::~GpgMEWorker() +{ + delete m_ctx; +} + +vector GpgMEWorker::FindKeys(const char * pattern, bool hasSecret, Error& e) const +{ + vector klst; + e = m_ctx->startKeyListing(pattern, hasSecret); + if (e.code() != 0) + return klst; + KeyListResult klr = m_ctx->keyListResult(); + if (klr.error().code() != 0) + { + e = klr.error(); + return klst; + } + while (e.code() == 0) + { + Key k = m_ctx->nextKey(e); + if (!k.isNull()) + { // What is that null key alongside ? + klst.push_back(k); + } + } + // e.code() != 0 here + klr = m_ctx->endKeyListing(); + e = klr.error(); + return klst; +} + +GpgME::Key GpgMEWorker::FindKey(const char * anyFullId, Error& e, bool secret) const +{ + return m_ctx->key(anyFullId, e, secret); +} + +const string GpgMEWorker::ImportKey(const char * filePath, Error& e) +{ + // Should we use a mutex here ? + FILE * kFp = fopen(filePath, "rb"); + GpgME::Data dKey(kFp); + vector keys = dKey.toKeys(); + if (keys.size() == 0) + { + fclose(kFp); + return ""; + } + const string keyid = string(dKey.toKeys().at(0).keyID()); // Must be done before import + ImportResult rImportKey = m_ctx->importKeys(dKey); + e = rImportKey.error(); + if (e.code() != 0) + { + fclose(kFp); + return ""; + } + + fclose(kFp); + return keyid; +} \ No newline at end of file diff --git a/GpgMEWorker.h b/GpgMEWorker.h new file mode 100644 index 0000000..ca62567 --- /dev/null +++ b/GpgMEWorker.h @@ -0,0 +1,59 @@ +/* + * File: GpgMEWorker.h + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 11 octobre 2019, 16:34 + */ + +#ifndef GPGMEWORKER_H +#define GPGMEWORKER_H + +#include +#include +#include +#include + +using namespace std; +using namespace GpgME; +/** + * Main class for GPGME OP, except deleting keys. + */ +class GpgMEWorker +{ +public: + GpgMEWorker(); + virtual ~GpgMEWorker(); + + /** + * Find keys corresponding to pattern. GPGME searches in many fields : + * keyid, fingerprint, name, email... + * @param pattern + * @param hasSecret + * @param e + * @return + */ + vector FindKeys(const char * pattern, bool hasSecret, Error& e) const; + /** + * Search for a single key fully identified : keyid, short keyid, fingerprint. + * @param anyFullId + * @param e + * @param secret + * @return + */ + GpgME::Key FindKey(const char * anyFullId, Error& e, bool secret = false) const; + /** + * Import a key from file. + * @param filePath + * @param e + * @return the keyid + */ + const string ImportKey(const char * filePath, Error& e); + +private: + Context * m_ctx; +}; + +#endif /* GPGMEWORKER_H */ + diff --git a/K7Main.cpp b/K7Main.cpp new file mode 100644 index 0000000..0a89a12 --- /dev/null +++ b/K7Main.cpp @@ -0,0 +1,470 @@ +/* + * File: K7Main.cpp + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 7 octobre 2019, 21:29 + */ + +#include "K7Main.h" +#include "global.h" +#include +#include +#include +#include +#include +#include +#include +#include "GpgMEWorker.h" +#include "GpgMECWorker.h" + +using namespace std; + +K7Main::K7Main(const WEnvironment& env) +: WApplication(env) +{ + m_config = NULL; + WApplication::setTitle(_APPNAME_); + const WString bundle = WApplication::appRoot() + _APPNAME_; + WApplication::instance()->messageResourceBundle().use(bundle.toUTF8()); + if (!env.javaScript() || !env.ajax()) + { + root()->addWidget(cpp14::make_unique(TR("NoJS"))); + WApplication::quit(WString::Empty); + } + // We want users to authenticate with an X509 certificate + if (WApplication::instance()->environment().sslInfo() == NULL) + { + root()->addWidget(cpp14::make_unique(TR("NoAuth"))); + WApplication::quit(WString::Empty); + } + // Translate UID trusts to string + UidValidities[UserID::Validity::Full] = TR("UidFull"); + UidValidities[UserID::Validity::Marginal] = TR("UidMarginal"); + UidValidities[UserID::Validity::Never] = TR("UidNever"); + UidValidities[UserID::Validity::Ultimate] = TR("UidUltimate"); + UidValidities[UserID::Validity::Undefined] = TR("UidUndefined"); + UidValidities[UserID::Validity::Unknown] = TR("UidUnknown"); + m_uploader = NULL; m_deleter = NULL; +} + +K7Main::~K7Main() +{ + delete m_config; delete m_uploader; delete m_deleter; +} + +void +K7Main::Create() +{ + WContainerWidget * cwHeader = new WContainerWidget(); + WHBoxLayout * hblHeader = new WHBoxLayout(); + cwHeader->setLayout(unique_ptr (hblHeader)); + hblHeader->addWidget(cpp14::make_unique(_APPNAME_)); + // Error messages will go here + m_tmwMessage = new TransientMessageWidget(); + m_tmwMessage->setTextAlignment(AlignmentFlag::Right); + hblHeader->addWidget(unique_ptr(m_tmwMessage)); + root()->addWidget(unique_ptr (cwHeader)); + hblHeader->setStretchFactor(m_tmwMessage, 1); + + /* + * Load config JSON file. + * On error, just abort, AppConfig will print an error message in m_tmwMessage + */ + m_config = new AppConfig(m_tmwMessage); + if (!m_config->LoadConfig()) + return; + + m_cwMain = new WContainerWidget(); + WGridLayout * grlMain = new WGridLayout(); + grlMain->setColumnStretch(0, 1); + grlMain->setColumnStretch(1, 0); + m_cwMain->setLayout(unique_ptr (grlMain)); + // Add a search zone : line edit and button + m_leSearch = new WLineEdit(); + grlMain->addWidget(unique_ptr (m_leSearch), 0, 0); + m_leSearch->enterPressed().connect(this, &K7Main::Search); + WPushButton * btnSearch = new WPushButton(TR("Search")); + btnSearch->setToolTip(TR("TTTSearch")); + grlMain->addWidget(unique_ptr (btnSearch), 0, 1); + btnSearch->clicked().connect(this, &K7Main::Search); + // Add a result zone as a tree table + m_ttbKeys = new WTreeTable(); + grlMain->addWidget(unique_ptr (m_ttbKeys), 1, 0); + + WContainerWidget * cwButtons = new WContainerWidget(); + WVBoxLayout * vblButtons = new WVBoxLayout(); + cwButtons->setLayout(unique_ptr (vblButtons)); + // Add an import button if current user is allowed + if (m_config->CanImport()) + { + m_btnUpload = new WPushButton(TR("Upload")); + m_btnUpload->setToolTip(TR("TTTUpload")); + vblButtons->addWidget(unique_ptr (m_btnUpload)); + m_btnUpload->clicked().connect(this, &K7Main::PopupUploader); + m_btnImport = new WPushButton(TR("Import")); + m_btnImport->setToolTip(TR("TTTImport")); + vblButtons->addWidget(unique_ptr (m_btnImport)); + m_btnImport->clicked().connect(this, &K7Main::DoImportKey); + m_btnImport->hide(); + } + // Add a delete button if current user is allowed + if (m_config->CanDelete()) + { + m_btnDelete = new WPushButton(TR("Delete")); + m_btnDelete->setToolTip(TR("TTTDelete")); + vblButtons->addWidget(unique_ptr (m_btnDelete)); + m_btnDelete->clicked().connect(this, &K7Main::PopupDeleter); + m_btnDelete->hide(); + } + vblButtons->addSpacing(300); + grlMain->addWidget(unique_ptr (cwButtons), 1, 1); + + // Add and hide detail tables + m_ttbUids = new WTreeTable(); + grlMain->addWidget(unique_ptr (m_ttbUids), 2, 0); + m_ttbUids->hide(); + m_ttbSubKeys = new WTreeTable(); + grlMain->addWidget(unique_ptr (m_ttbSubKeys), 3, 0); + m_ttbSubKeys->hide(); + + root()->addWidget(cpp14::make_unique()); + root()->addWidget(unique_ptr (m_cwMain)); +#ifdef DEVTIME + // Save my fingertips. + m_leSearch->setText("s"); +#endif +} + +void K7Main::Search() +{ +#ifndef DEVTIME + // A reasonable minimal search criteria + if (!m_leSearch->text().empty() && m_leSearch->text().toUTF8().length() < 3) + { + m_tmwMessage->SetText(TR("CriteriaTooShort")); + return; + } +#endif + m_ttbSubKeys->hide(); + m_ttbUids->hide(); + Error e; + vector configPrivKeys = m_config->PrivateKeyIds(); + GpgMEWorker gpgw; + vector privkList, pubkList; + + // Find private keys if any is declared in config file for current user. + for (uint i = 0; i < configPrivKeys.size(); i++) + { + /* + * User may manage more than one private key. + * configPrivKeys.at(i) : we want this to be a full key id(short, normal or fpr) + * But it can be any string in the config file (name, email...). + * lst can hence contain many keys. + */ + vector lst = gpgw.FindKeys(configPrivKeys.at(i).toUTF8().c_str(), true, e); + if (e.code() != 0) + { + privkList.clear(); + m_tmwMessage->SetText(e.asString()); + return; + } + /* + * If any key is not a full key id, abort. + */ + for (uint j = 0; j < lst.size(); j++) + { + const GpgME::Key k = lst.at(j); + if (!ConfigKeyIdMatchesKey(k, configPrivKeys.at(i))) + { + m_tmwMessage->SetText(configPrivKeys.at(i) + TR("BadConfigKeyId")); + privkList.clear(); + return; + } + privkList.push_back(k); + } + } + // Find public keys as per criteria + if (!m_leSearch->text().empty()) + { + pubkList = gpgw.FindKeys(m_leSearch->text().toUTF8().c_str(), false, e); + if (e.code() != 0) + { + pubkList.clear(); + m_tmwMessage->SetText(e.asString()); + return; + } + } + + if (m_ttbKeys->columnCount() == 1) { + m_ttbKeys->addColumn(TR("ID"), 120); + m_ttbKeys->addColumn(TR("Fpr"), 300); + } + // The previous tree root is auto deleted by the use of smart pointers !! + WTreeTableNode * rootNode = new WTreeTableNode(TR("Keys")); + rootNode->setChildCountPolicy(ChildCountPolicy::Enabled); + m_ttbKeys->setTreeRoot(unique_ptr (rootNode), TR("KeyRing")); + rootNode->expand(); + // Show available keys + if (pubkList.size()) + DisplayKeys(pubkList, TR("Publics"), true); + if (privkList.size() && m_config->PrivateKeyIds().size() > 0) + DisplayKeys(privkList, TR("Secrets"), false); +} + +bool K7Main::ConfigKeyIdMatchesKey(const GpgME::Key& k, const WString& configKeyId) const +{ + // We want key identifier in config file to be real and complete. + return (configKeyId == WString(k.shortKeyID()) + || configKeyId == WString(k.keyID()) + || configKeyId == WString(k.primaryFingerprint())); +} + +WString K7Main::MakeDateTimeLabel(time_t ticks) +{ + std::chrono::minutes offset = WApplication::instance()->environment().timeZoneOffset(); + const WDateTime dt = WDateTime::fromTime_t(ticks + (time_t) offset.count() * 60); + return dt.toString(WString("yyyy-MM-dd - hh:mm:ss")); +} + +void K7Main::DisplayKeys(const vector& kList, const WString& grpLabel, bool expand) +{ + WTreeTableNode * grpNode = new WTreeTableNode(grpLabel); + m_ttbKeys->treeRoot()->addChildNode(unique_ptr (grpNode)); + for (uint i = 0; i < kList.size(); i++) + { + const GpgME::Key k = kList.at(i); + WTreeTableNode * keyNode = new WTreeTableNode(k.userID(0).name()); + WLink ln; + ln.setUrl(WString(L"javascript:void(0)").toUTF8()); + WAnchor * anc = new WAnchor(ln, k.shortKeyID()); + anc->setId(k.shortKeyID()); + // We use widget attribute values to buffer properties. + anc->setAttributeValue("hasSecret", k.hasSecret() ? "1" : "0"); + anc->clicked().connect(std::bind(&K7Main::OnKeyAnchorClicked, this, anc)); + keyNode->setColumnWidget(1, unique_ptr (anc)); + keyNode->setColumnWidget(2, cpp14::make_unique (k.primaryFingerprint())); + grpNode->addChildNode(unique_ptr (keyNode)); + } + if (expand) + grpNode->expand(); +} + +void K7Main::OnKeyAnchorClicked(WAnchor * source) +{ + // Show key details + const WString hasSecret = source->attributeValue("hasSecret"); + bool secret = true; + if (hasSecret == WString("0")) + secret = false; + const string id = source->id(); + DisplayUids(id, secret); + DisplaySubKeys(id, secret); + if (m_config->CanDelete()) // m_btnDelete is NULL otherwise + m_btnDelete->setHidden(!CanKeyBeDeleted(id)); +} + +void K7Main::DisplayUids(const WString& fullKeyID, bool secret) +{ + // Show UID details for a key + Error e; + GpgMEWorker gpgw; + m_ttbUids->hide(); + const GpgME::Key k = gpgw.FindKey(fullKeyID.toUTF8().c_str(), e, secret); + if (e.code() != 0) + { + m_tmwMessage->SetText(e.asString()); + return; + } + if (m_ttbUids->columnCount() == 1) + { + m_ttbUids->addColumn(TR("Email"), 200); + m_ttbUids->addColumn(TR("Trust"), 100); + m_ttbUids->addColumn(TR("Comment"), 300); + } + WTreeTableNode * rootNode = new WTreeTableNode(fullKeyID); + rootNode->setChildCountPolicy(ChildCountPolicy::Enabled); + m_ttbUids->setTreeRoot(unique_ptr (rootNode), TR("UIDs")); + rootNode->expand(); + for (uint i = 0; i < k.numUserIDs(); i++) + { + UserID uid = k.userID(i); + WTreeTableNode * uidNode = new WTreeTableNode(uid.name()); + uidNode->setColumnWidget(1, cpp14::make_unique (uid.email())); + uidNode->setColumnWidget(2, cpp14::make_unique (UidValidities[uid.validity()])); + uidNode->setColumnWidget(3, cpp14::make_unique (uid.comment())); + rootNode->addChildNode(unique_ptr (uidNode)); + // uid.numSignatures() is always 0, even for signed keys ! + for (uint s = 0; s < uid.numSignatures(); s++) + { + UserID::Signature sig = uid.signature(s); + const WString signer = WString(sig.signerName()) + _SPACE_ + + WString(sig.signerKeyID()); + WTreeTableNode * sigNode = new WTreeTableNode(signer); + sigNode->setColumnWidget(1, cpp14::make_unique (sig.signerEmail())); + WString exp = TR("Expiration") + _SPACE_ + _COLON_ + _SPACE_; + exp += sig.neverExpires() ? TR("Never") : MakeDateTimeLabel(sig.expirationTime()); + sigNode->setColumnWidget(2, cpp14::make_unique (exp)); + sigNode->setColumnWidget(3, cpp14::make_unique (sig.signerComment())); + uidNode->addChild(unique_ptr (sigNode)); + } + } + m_ttbUids->show(); +} + +void K7Main::DisplaySubKeys(const WString& fullKeyID, bool secret) +{ + // Show subkey details for a key + Error e; + GpgMEWorker gpgw; + m_ttbSubKeys->hide(); + const GpgME::Key k = gpgw.FindKey(fullKeyID.toUTF8().c_str(), e, secret); + if (e.code() != 0) + { + m_tmwMessage->SetText(e.asString()); + return; + } + if (m_ttbSubKeys->columnCount() == 1) + { + m_ttbSubKeys->addColumn(TR("Fpr"), 300); + m_ttbSubKeys->addColumn(TR("Expiration"), 150); + m_ttbSubKeys->addColumn(TR("Usage"), 70); + m_ttbSubKeys->addColumn(TR("Secret"), 50); + } + WTreeTableNode * rootNode = new WTreeTableNode(fullKeyID); + rootNode->setChildCountPolicy(ChildCountPolicy::Enabled); + m_ttbSubKeys->setTreeRoot(unique_ptr (rootNode), TR("SubKeys")); + rootNode->expand(); + for (uint i = 0; i < k.numSubkeys(); i++) + { + Subkey sk = k.subkey(i); + WTreeTableNode * skNode = new WTreeTableNode(sk.keyID()); + skNode->setColumnWidget(1, cpp14::make_unique (sk.fingerprint())); + WString exp = sk.neverExpires() ? TR("Never") : MakeDateTimeLabel(sk.expirationTime()); + skNode->setColumnWidget(2, cpp14::make_unique (exp)); + WString usage = sk.canAuthenticate() ? WString("A") : WString::Empty; + usage += sk.canCertify() ? WString("C") : WString::Empty; + usage += sk.canEncrypt() ? WString("E") : WString::Empty; + usage += sk.canSign() ? WString("S") : WString::Empty; + skNode->setColumnWidget(3, cpp14::make_unique (usage)); + const WString isSecret = sk.isSecret() ? TR("Yes") : TR("No"); + skNode->setColumnWidget(4, cpp14::make_unique (isSecret)); + rootNode->addChildNode(unique_ptr (skNode)); + } + m_ttbSubKeys->show(); +} + +void K7Main::PopupUploader() { + if (m_uploader == NULL) { + m_uploader = new Uploader(m_btnUpload, m_tmwMessage); + m_uploader->Create(); + m_uploader->UploadDone().connect(this, &K7Main::OnUploadCompleted); + } + m_uploader->show(); +} + +void K7Main::OnUploadCompleted(const WString& spool) { + // Buffer the spool file name in the import button + m_btnImport->setAttributeValue("spool", spool); + m_btnImport->show(); + m_uploader->hide(); +} + +void K7Main::DoImportKey() { + const WString spool = m_btnImport->attributeValue("spool"); + Error e; + GpgMEWorker gpgw; + const WString keyid = gpgw.ImportKey(spool.toUTF8().c_str(), e); + m_btnImport->hide(); + m_btnImport->setAttributeValue("spool", ""); + if (e.code() != 0) { + m_tmwMessage->SetText(e.asString()); + return; + } + if (keyid.empty()) { + m_tmwMessage->SetText(TR("ImportError") + keyid); + return; + } + // Show the imported key + GpgME::Key k = gpgw.FindKey(keyid.toUTF8().c_str(), e, false); // A public is present anyway + if (e.code() != 0) { + m_tmwMessage->SetText(e.asString()); + return; + } + m_tmwMessage->SetText(TR("ImportSuccess") + keyid + WString(" - ") + WString(k.userID(0).name())); + m_leSearch->setText(keyid); + Search(); +} + +bool K7Main::CanKeyBeDeleted(const WString& fullKeyID) { + // Caller should check m_config->canDelete first. m_btnDelete is null if can't delete. + Error e; + GpgMEWorker gpgw; + GpgME::Key k = gpgw.FindKey(fullKeyID.toUTF8().c_str(), e, true); // Look for a private key + if (e.code() != 0 && e.code() != 16383) { // 16383 : end of file, when key is not private + m_tmwMessage->SetText(e.asString()); + return false; + } + // k can now be secret or public + if (k.isNull()) {// Is a public key + k = gpgw.FindKey(fullKeyID.toUTF8().c_str(), e, false); + // Prepare actual delete + m_btnDelete->setAttributeValue("keyid", k.keyID()); + m_btnDelete->setAttributeValue("hasSecret", "0"); + return true; + } + /* + * k is now secret + * Is selected private key one of those that the current user manages ? + */ + vector curUserPrivKeys = m_config->PrivateKeyIds(); + vector::iterator it; + for (it = curUserPrivKeys.begin(); it != curUserPrivKeys.end(); it++) { + if (ConfigKeyIdMatchesKey(k, *it)) { + m_btnDelete->setAttributeValue("keyid", k.keyID()); + m_btnDelete->setAttributeValue("hasSecret", "1"); + return true; + } + } + return false; +} + +void K7Main::PopupDeleter() { + if (m_deleter == NULL) { + m_deleter = new Deleter(m_btnDelete, m_tmwMessage); + m_deleter->Create(); + m_deleter->GetDeleteButton()->clicked().connect(this, &K7Main::DoDeleteKey); + } + m_deleter->show(); +} + +void K7Main::DoDeleteKey() { + // Deleting keys requires the GPGME C API + Error c_e, e; + GpgMECWorker gpgcw; + GpgMEWorker gpgw; + const WString fullKeyID = m_btnDelete->attributeValue("keyid"); + const WString hasSecret = m_btnDelete->attributeValue("hasSecret"); + bool secret = true; + if (hasSecret == WString("0")) + secret = false; + // Get the key before deletion, to show its ID on success + GpgME::Key k = gpgw.FindKey(fullKeyID.toUTF8().c_str(), e, secret); + if (e.code() != 0) { + m_tmwMessage->SetText(e.asString()); + return; + } + // Delete the key using the C API + bool res = gpgcw.DeleteKey(fullKeyID.toUTF8().c_str(), secret, c_e); + if (c_e.code() != 0) { + m_tmwMessage->SetText(c_e.asString()); + } else { + m_tmwMessage->SetText(TR("DeleteSuccess") + fullKeyID + WString(" - ") + WString(k.userID(0).name())); + } + m_btnDelete->hide(); + m_deleter->hide(); + // Show that the key is no longer available + m_leSearch->setText(fullKeyID); + Search(); +} diff --git a/K7Main.h b/K7Main.h new file mode 100644 index 0000000..ad05cd9 --- /dev/null +++ b/K7Main.h @@ -0,0 +1,128 @@ +/* + * File: K7Main.h + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 7 octobre 2019, 21:29 + */ + +#ifndef K7MAIN_H +#define K7MAIN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppConfig.h" +#include "PopupUploader.h" +#include "PopupDeleter.h" +#include "TransientMessageWidget.h" + +using namespace Wt; + +class K7Main : public WApplication +{ +public: + K7Main(const WEnvironment& env); + virtual ~K7Main(); + void Create(); + +private: + /** + * Translate UID trusts to string + */ + typedef map UidValidityMap; + UidValidityMap UidValidities; + AppConfig * m_config; + WGridLayout * m_grlMain; + WContainerWidget * m_cwMain; + TransientMessageWidget * m_tmwMessage; + WLineEdit * m_leSearch; + WPushButton * m_btnUpload; + WPushButton * m_btnImport; + WPushButton * m_btnDelete ; + WTreeTable * m_ttbKeys; + WTreeTable * m_ttbUids; + WTreeTable * m_ttbSubKeys; + Uploader * m_uploader; + Deleter * m_deleter; + /** + * Finds public keys as per criteria, + * and private keys if any is declared in config file for current client. + * \nShows the keys in tree table. + */ + void Search(); + /** + * We want key identifier in config file to be real and complete. + * @param k + * @param configKeyId key identifier as entered in configuration file + * @return + */ + bool ConfigKeyIdMatchesKey(const GpgME::Key& k, const WString& configKeyId) const; + /** + * Show keys in tree table + */ + void DisplayKeys(const vector& kList, const WString& grpLabel, bool expand); + /** + * Show key details + * @param source + */ + void OnKeyAnchorClicked(WAnchor * source); + /** + * Show UID details for a key + * @param fullKeyID + * @param secret + */ + void DisplayUids(const WString& fullKeyID, bool secret = false); + /** + * Show subkey details for a key + * @param fullKeyID + * @param secret + */ + void DisplaySubKeys(const WString& fullKeyID, bool secret = false); + /** + * Shows a non-blocking popup to upload a key, + * with forward confirmation for upload. + */ + void PopupUploader(); + /** + * Shows a button to import an uploaded key + * @param spool + */ + void OnUploadCompleted(const WString& spool); + /** + * Actually import the uploaded file. + */ + void DoImportKey(); + /** + * Shows a non-blocking popup to delete a key + */ + void PopupDeleter(); + /** + * All public keys can be deleted. + * Private keys can be deleted only if the user + * manages that key, as declared in the configuration file. + * @param fullKeyID + * @return + */ + bool CanKeyBeDeleted(const WString& fullKeyID); + /** + * Actually delete the key, with forward confirmation in the popup. + */ + void DoDeleteKey(); + /** + * Translates unit time to readable date. + */ + WString MakeDateTimeLabel(time_t ticks); +}; + +#endif /* K7MAIN_H */ + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05de621 --- /dev/null +++ b/Makefile @@ -0,0 +1,128 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# Available make variables: +# +# CND_BASEDIR base directory for relative paths +# CND_DISTDIR default top distribution directory (build artifacts) +# CND_BUILDDIR default top build directory (object files, ...) +# CONF name of current configuration +# CND_PLATFORM_${CONF} platform name (current configuration) +# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) +# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) +# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) +# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) +# CND_PACKAGE_NAME_${CONF} name of package (current configuration) +# CND_PACKAGE_PATH_${CONF} path to package (current configuration) +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin + + +# build +build: .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: .build-impl +# Add your post 'build' code here... + + +# clean +clean: .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: .clean-impl +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: .clobber-impl +# Add your post 'clobber' code here... + + +# all +all: .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: .all-impl +# Add your post 'all' code here... + + +# build tests +build-tests: .build-tests-post + +.build-tests-pre: +# Add your pre 'build-tests' code here... + +.build-tests-post: .build-tests-impl +# Add your post 'build-tests' code here... + + +# run tests +test: .test-post + +.test-pre: build-tests +# Add your pre 'test' code here... + +.test-post: .test-impl +# Add your post 'test' code here... + + +# help +help: .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: .help-impl +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk + +# include project make variables +include nbproject/Makefile-variables.mk diff --git a/PopupDeleter.cpp b/PopupDeleter.cpp new file mode 100644 index 0000000..27f9b8b --- /dev/null +++ b/PopupDeleter.cpp @@ -0,0 +1,62 @@ +/* + * File: PopupDeleter.cpp + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 15 octobre 2019, 18:39 + */ + +#include "PopupDeleter.h" +#include "global.h" +#include +#include + +using namespace std; + +Deleter::Deleter(WWidget * anchorWidget, TransientMessageWidget * txtMessage, const WLength& width) +: WPopupWidget(cpp14::make_unique()) { + m_tmwMessage = txtMessage; m_cwMain = NULL; m_cbConfirm = NULL; + m_cbReConfirm = NULL; m_btnDelete = NULL; + setTransient(true); + setAnchorWidget(anchorWidget); + setWidth(width); +} + +Deleter::~Deleter() { +} + +void Deleter::Create() { + m_cwMain = static_cast (implementation()); + WVBoxLayout * vblMain = new WVBoxLayout(); + m_cwMain->setLayout(unique_ptr (vblMain)); + m_cbConfirm = new WCheckBox(TR("Confirm")); + vblMain->addWidget(unique_ptr (m_cbConfirm)); + m_cbReConfirm = new WCheckBox(TR("ReConfirm")); + vblMain->addWidget(unique_ptr (m_cbReConfirm)); + m_btnDelete = new WPushButton(TR("Delete")); + vblMain->addWidget(unique_ptr (m_btnDelete)); + m_cbReConfirm->hide(); + m_btnDelete->hide(); + m_cbConfirm->changed().connect(this, &Deleter::OnCbConfirm); + m_cbReConfirm->changed().connect(this, &Deleter::OnCbReConfirm); + this->hidden().connect(this, &Deleter::Reset); +} + +void Deleter::Reset() { + m_btnDelete->hide(); + m_cbReConfirm->setUnChecked(); + m_cbReConfirm->hide(); + m_cbConfirm->setUnChecked(); + m_cbConfirm->show(); +} + +void Deleter::OnCbConfirm() { + m_cbReConfirm->setHidden(m_cbConfirm->checkState() != CheckState::Checked); + m_cbReConfirm->setUnChecked(); + m_btnDelete->setHidden(m_cbReConfirm->checkState() != CheckState::Checked); +} + +void Deleter::OnCbReConfirm() { + m_btnDelete->setHidden(m_cbReConfirm->checkState() != CheckState::Checked); +} diff --git a/PopupDeleter.h b/PopupDeleter.h new file mode 100644 index 0000000..fcfbd76 --- /dev/null +++ b/PopupDeleter.h @@ -0,0 +1,48 @@ +/* + * File: PopupDeleter.h + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 15 octobre 2019, 18:39 + */ + +#ifndef POPUPDELETER_H +#define POPUPDELETER_H + +#include +#include +#include +#include +#include "TransientMessageWidget.h" + +using namespace Wt; +/** + * A transient popup window with a forward confirmation + * before deleting a key. + */ +class Deleter : public WPopupWidget { +public: + Deleter(WWidget * anchorWidget, TransientMessageWidget * txtMessage, const WLength& width = 350); + virtual ~Deleter(); + void Create(); + /** + * Caller can bind the delete function to this button. + * @return + */ + WPushButton* GetDeleteButton() {return m_btnDelete;} +private: + TransientMessageWidget * m_tmwMessage; + WContainerWidget * m_cwMain; + WCheckBox * m_cbConfirm; + WCheckBox * m_cbReConfirm; + WPushButton * m_btnDelete; + + // Visibility management + void Reset(); + void OnCbConfirm(); + void OnCbReConfirm(); +}; + +#endif /* POPUPDELETER_H */ + diff --git a/PopupUploader.cpp b/PopupUploader.cpp new file mode 100644 index 0000000..ab654a0 --- /dev/null +++ b/PopupUploader.cpp @@ -0,0 +1,92 @@ +/* + * File: PopupUploader.cpp + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 13 octobre 2019, 18:48 + */ + +#include "PopupUploader.h" +#include "global.h" +#include +#include + +using namespace std; + +Uploader::Uploader(WWidget * anchorWidget, TransientMessageWidget * txtMessage, const WLength& width) +: WPopupWidget(cpp14::make_unique()) { + m_tmwMessage = txtMessage; m_upload = NULL; m_cwMain = NULL; + m_cbConfirm = NULL; m_cbReConfirm = NULL; m_btnUpload = NULL; + setTransient(true); + setAnchorWidget(anchorWidget); + setWidth(width); +} + +Uploader::~Uploader() { +} + +void Uploader::Create() { + m_upload = new WFileUpload(); + m_upload->setFileTextSize(10240); // Is really approximate + m_upload->setMultiple(false); + m_cwMain = static_cast (implementation()); + WVBoxLayout * vblMain = new WVBoxLayout(); + m_cwMain->setLayout(unique_ptr (vblMain)); + vblMain->addWidget(unique_ptr (m_upload)); + m_cbConfirm = new WCheckBox(TR("Confirm")); + vblMain->addWidget(unique_ptr (m_cbConfirm)); + m_cbReConfirm = new WCheckBox(TR("ReConfirm")); + vblMain->addWidget(unique_ptr (m_cbReConfirm)); + m_btnUpload = new WPushButton(TR("Upload")); + vblMain->addWidget(unique_ptr (m_btnUpload)); + m_cbReConfirm->hide(); + m_cbConfirm->hide(); + m_btnUpload->hide(); + m_cbConfirm->changed().connect(this, &Uploader::OnCbConfirm); + m_cbReConfirm->changed().connect(this, &Uploader::OnCbReConfirm); + m_btnUpload->clicked().connect(this, &Uploader::DoUpload); + m_upload->uploaded().connect(this, &Uploader::OnUploadDone); + m_upload->fileTooLarge().connect(this, &Uploader::OnFileTooLarge); + m_upload->changed().connect(this, &Uploader::Reset); + this->hidden().connect(this, &Uploader::Reset); +} + +void Uploader::Reset() { + m_btnUpload->hide(); + m_cbReConfirm->setUnChecked(); + m_cbReConfirm->hide(); + m_cbConfirm->setUnChecked(); + m_cbConfirm->show(); + m_btnUpload->enable(); +} +void Uploader::OnCbConfirm() { + m_cbReConfirm->setHidden(m_cbConfirm->checkState() != CheckState::Checked); + m_cbReConfirm->setUnChecked(); + m_btnUpload->setHidden(m_cbReConfirm->checkState() != CheckState::Checked); +} + +void Uploader::OnCbReConfirm() { + m_btnUpload->setHidden(m_cbReConfirm->checkState() != CheckState::Checked); +} + +void Uploader::DoUpload() { + if (m_upload->canUpload()) { + m_btnUpload->disable(); + m_upload->upload(); + } else { + m_tmwMessage->SetText(TR("CantUpload")); + } +} + +void Uploader::OnUploadDone() { + m_sigUploadDone.emit(m_upload->spoolFileName()); + m_btnUpload->enable(); +} + +void Uploader::OnFileTooLarge() { + m_tmwMessage->SetText(TR("FileTooLarge")); + m_btnUpload->enable(); +} + + diff --git a/PopupUploader.h b/PopupUploader.h new file mode 100644 index 0000000..bbca4e6 --- /dev/null +++ b/PopupUploader.h @@ -0,0 +1,63 @@ +/* + * File: PopupUploader.h + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 13 octobre 2019, 18:48 + */ + +#ifndef POPUPUPLOADER_H +#define POPUPUPLOADER_H + +#include +#include +#include +#include +#include +#include +#include "TransientMessageWidget.h" + +using namespace Wt; +/** + * A transient popup window to upload a key + * that will next be imported. + * @param anchorWidget + * @param txtMessage + * @param width + */ +class Uploader : public WPopupWidget +{ +public: + Uploader(WWidget * anchorWidget, TransientMessageWidget * txtMessage, const WLength& width = 350); + virtual ~Uploader(); + void Create(); + + /** + * Forward WFileUpload::uploaded() to caller + * @return + */ + Signal& UploadDone() + { + return m_sigUploadDone; + } +private: + TransientMessageWidget * m_tmwMessage; + WFileUpload * m_upload; + WContainerWidget * m_cwMain; + WCheckBox * m_cbConfirm; + WCheckBox * m_cbReConfirm; + WPushButton * m_btnUpload; + Signal m_sigUploadDone; + + void Reset(); + void OnCbConfirm(); + void OnCbReConfirm(); + void DoUpload(); + void OnUploadDone(); + void OnFileTooLarge(); + +}; + +#endif /* POPUPUPLOADER_H */ + diff --git a/README.md b/README.md new file mode 100644 index 0000000..bf38dae --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +K7 is an application for minimal remote management of GPG keys on a web server. +It allows to view, import and delete keys. +It does not intend nor need to be a full blown key manager. +Key generation and editing is not implemented, and it probably cannot be done this way. + +K7 is developed as a NetBeans project on the [WebToolkit](https://www.webtoolkit.eu/)(Wt) libraries. +It is released under the GPL version 2 license. + +The intent is solely to add and delete keys in the default GPG keyring of the running user. +These keys can then be used by other Wt applications, or applications based on other libraries, to encrypt and sign data. As such, it suits my personal needs. + +BUILDING + +As a NetBeans project, a Makefile exists in the project root. +cd /path/to/K7 +make CONF=Debug #linked to wthttp here +make CONF=Release #linked to wtfcgi + +INSTALLING AND RUNNING + +Please see Wt's manuals about the modes of installing and running Wt applications. +In particular, K7 needs the enviromment variable WT_APP_ROOT that should point to the directory containing configuration and translation files. In the project's tree, it's WTAPPROOT/K7. + +MAIN CONFIGURATION FILE + +This file is hard coded as k7config.json, and must be found in WT_APP_ROOT. +It controls access to the application. All users must authenticate by sending a client X509 certificate, and access is allowed if the subject's common name is listed as a JSON key in the configuration file. +An allowed user can always view keys. He can optionally import any GPG key, and delete GPG public keys. +An allowed user can optionally delete private GPG keys. For this, a full key identifier must be declared in a JSON array in the configuration file. This should be a normal key identifier, a short key identifier or a fingerprint, but always a full identifier. + +TRANSLATION FILES + +K7.xml contains user facing strings for English default language. K7_fr.xml is translated in French . + +DISCLAIMER + +As usual, use at your own risks or don't use. I don't claim that K7 is fit for any purpose. Programming is just my hobby. diff --git a/TransientMessageWidget.cpp b/TransientMessageWidget.cpp new file mode 100644 index 0000000..2d09833 --- /dev/null +++ b/TransientMessageWidget.cpp @@ -0,0 +1,71 @@ +/* + * File: TransientMessageWidget.cpp + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 16 octobre 2019, 18:25 + */ + +#include "TransientMessageWidget.h" + +TransientMessageWidget::TransientMessageWidget() +: WText() +{ + Init(); +} + +TransientMessageWidget::TransientMessageWidget(const WString& text) +: WText(text) +{ + Init(); +} + +TransientMessageWidget::TransientMessageWidget(const WString& text, TextFormat textFormat) +: WText(text, textFormat) +{ + Init(); +} + +TransientMessageWidget::~TransientMessageWidget() +{ + m_timer.stop(); +} + +void TransientMessageWidget::Init() +{ + m_stackSize = 8; + m_interval = (std::chrono::milliseconds) 10 * 1000; + m_timer.setSingleShot(true); + SetInterval(m_interval); + m_timer.timeout().connect(this, &TransientMessageWidget::OnTimer); +} + +void TransientMessageWidget::OnTimer() +{ + WText::setText(WString::Empty); +} + +void TransientMessageWidget::SetText(const WString& text, bool stack) +{ + m_timer.stop(); + if (stack) { + // Remove the oldest message if stack is full + if (m_stack.size() == m_stackSize) { + m_stack.pop_back(); + } + m_stack.push_front(text); + } + WText::setText(text); + // List messages in the tool tip + WString ttt = WString::Empty; + list::iterator it; + uint idx = m_stack.size(); + for (it = m_stack.begin(); it != m_stack.end(); it++) + { + ttt += WString(to_string(idx)) + WString(". ") + *it + WString("\n"); + idx--; + } + setToolTip(ttt); + m_timer.start(); +} \ No newline at end of file diff --git a/TransientMessageWidget.h b/TransientMessageWidget.h new file mode 100644 index 0000000..d8990c7 --- /dev/null +++ b/TransientMessageWidget.h @@ -0,0 +1,69 @@ +/* + * File: TransientMessageWidget.h + * Author: SET - nmset@netcourrier.com + * License : LGPL v2.1 + * Copyright SET - © 2019 + * + * Created on 16 octobre 2019, 18:25 + */ + +#ifndef TRANSIENTMESSAGEWIDGET_H +#define TRANSIENTMESSAGEWIDGET_H + +#include +#include +#include + +using namespace Wt; +using namespace std; + +/** + * A transient stacked message zone. + * By default, 8 messages can be stacked in a list shown + * in the tool tip; each message is shown for 10 seconds. + */ +class TransientMessageWidget : public WText +{ +public: + TransientMessageWidget(); + TransientMessageWidget(const WString& text); + TransientMessageWidget(const WString& text, TextFormat textFormat); + virtual ~TransientMessageWidget(); + + void SetInterval(std::chrono::milliseconds interval) + { + m_timer.setInterval(interval); + } + + std::chrono::milliseconds Interval() + { + return m_timer.interval(); + } + + void SetStackSize(uint sz) + { + m_stackSize = sz; + } + + uint GetStackSize() + { + return m_stackSize; + } + /** + * Main function to show and pile up messages. + * @param text + * @param stack + */ + void SetText(const WString& text, bool stack = true); +private: + uint m_stackSize; + std::chrono::milliseconds m_interval; + WTimer m_timer; + list m_stack; + + void Init(); + void OnTimer(); +}; + +#endif /* TRANSIENTMESSAGEWIDGET_H */ + diff --git a/WTAPPROOT/K7/K7.xml b/WTAPPROOT/K7/K7.xml new file mode 100644 index 0000000..16e24ba --- /dev/null +++ b/WTAPPROOT/K7/K7.xml @@ -0,0 +1,65 @@ + + + + Browser does not provide Javascript or AJAX + Browser does not send a client certificate + Search + Upload + Import + Delete + Sign key + Find keys with this pattern + Upload a new key + Add a new key + Delete selected key + Sign selected key with your secret key if available + Can't upload + + Can't load config file + Can't parse json file + Can't identify certificates in config file + in configuration file is not a valid key identifier + Access denied + + Keyring + Key + Keys + Public + Public + Secret + Secret + Fingerprint + + ID + User ID + User IDs + Email + Validity + Trust + + Full + Marginal + Never + Ultimate + Undefined + Unknown + Comment + Signers + Expiration + Never + + Subkeys + IDs + Usage + + Yes + No + At least 3 characters required, or use an empty criteria to list your private keys if any + + Confirm + Confirm again + File is too big + Import success : + Uploaded file could not be imported in the keyring + Delete success : + \ No newline at end of file diff --git a/WTAPPROOT/K7/K7_fr.xml b/WTAPPROOT/K7/K7_fr.xml new file mode 100644 index 0000000..b74e1fc --- /dev/null +++ b/WTAPPROOT/K7/K7_fr.xml @@ -0,0 +1,65 @@ + + + + Javascript or AJAX manquant dans le navigateur + Le navigateur ne s'est pas authentifié + Rechercher + Télécharger + Importer + Supprimer + Signer + Rechercher des clés correspondant au motif + Télécharger une nouvelle clé + Ajouter une nouvelle clé au porte clés + Supprimer la clé sélectionnée + Signer la clé sélectionnée avec votre clé secrète si elle est disponible + Ne peut télécharger + + Ne peut charger le fichier de configuration + Ne peur traiter le fichier de configuration + Ne peut trouver les certificats d'identité dans le fichier de configuration + dans le fichier de configuration n'est pas un identifiant de clé valide + Accès non autorisé + + Porte clés + Clé + Clés + Publique + Publiques + Secrète + Secrètes + Empreinte + + Identifiant + Identifiant utilisateur + Identifiants utilisateur + Courriel + Validité + Confiance + + Complète + Marginale + Jamais + Ultime + Non définie + Inconnue + Commentaires + Signataires + Expiration + Jamais + + Sous-clés + IDs + Utilisation + + Oui + Non + Au moins 3 caractères requis, ou aucin critère pour sélectionner vos clés privées si elles sont déclarées + + Confirmer + Reconfirmer + Fichier trop volumineux + Importation réussie : + Le fichier téléchargé n'a pu être importé dans le trousseau + Suppression réussie : + diff --git a/WTAPPROOT/K7/k7config.json b/WTAPPROOT/K7/k7config.json new file mode 100644 index 0000000..0623526 --- /dev/null +++ b/WTAPPROOT/K7/k7config.json @@ -0,0 +1,15 @@ +{ + "sCommonName" : { + "user1" : { + "canImport" : true, + "canDelete" : true, + "privKeyIds" : [ + "FullKeyId1", + "FullKeyId2" + ] + }, + "user2" : { + "canImport" : true + } + } +} diff --git a/global.h b/global.h new file mode 100644 index 0000000..3725914 --- /dev/null +++ b/global.h @@ -0,0 +1,26 @@ +/* + * File: global.h + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 8 octobre 2019, 20:52 + */ + +#ifndef GLOBAL_H +#define GLOBAL_H + +#include +using namespace Wt; +using namespace std; + +#define TR(sk) WString::tr(sk) + +const WString _APPNAME_("K7"); +const WString _APPVERSION_("1"); +const WString _SPACE_(" "); +const WString _COLON_(":"); + + +#endif /* GLOBAL_H */ + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..cbf4e77 --- /dev/null +++ b/main.cpp @@ -0,0 +1,31 @@ +/* + * File: main.cpp + * Author: SET - nmset@netcourrier.com + * License : GPL v2 + * Copyright SET - © 2019 + * + * Created on 7 octobre 2019, 21:06 + */ + +#include +#include "K7Main.h" +#include +#include +#include +using namespace std; +using namespace Wt; + + +unique_ptr createApplication(const WEnvironment& env) +{ + unique_ptr app = cpp14::make_unique(env); + app->Create(); + return (app); +} + +int main(int argc, char** argv) +{ + GpgME::initializeLibrary(); + return WRun(argc, argv, &createApplication); +} + diff --git a/nbproject/Makefile-ARM-Release.mk b/nbproject/Makefile-ARM-Release.mk new file mode 100644 index 0000000..c24c1bd --- /dev/null +++ b/nbproject/Makefile-ARM-Release.mk @@ -0,0 +1,125 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +GREP=grep +NM=nm +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux +CND_DLIB_EXT=so +CND_CONF=ARM-Release +CND_DISTDIR=dist +CND_BUILDDIR=build + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/AppConfig.o \ + ${OBJECTDIR}/GpgMECWorker.o \ + ${OBJECTDIR}/GpgMEWorker.o \ + ${OBJECTDIR}/K7Main.o \ + ${OBJECTDIR}/PopupDeleter.o \ + ${OBJECTDIR}/PopupUploader.o \ + ${OBJECTDIR}/TransientMessageWidget.o \ + ${OBJECTDIR}/main.o + + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-Wno-deprecated -Wno-deprecated-declarations +CXXFLAGS=-Wno-deprecated -Wno-deprecated-declarations + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS=-L/usr/local/Wt/lib -lwt -lwtfcgi -lgpgmepp -lgpgme + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 + +${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7: ${OBJECTFILES} + ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 ${OBJECTFILES} ${LDLIBSOPTIONS} -s + +${OBJECTDIR}/AppConfig.o: AppConfig.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/AppConfig.o AppConfig.cpp + +${OBJECTDIR}/GpgMECWorker.o: GpgMECWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMECWorker.o GpgMECWorker.cpp + +${OBJECTDIR}/GpgMEWorker.o: GpgMEWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMEWorker.o GpgMEWorker.cpp + +${OBJECTDIR}/K7Main.o: K7Main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/K7Main.o K7Main.cpp + +${OBJECTDIR}/PopupDeleter.o: PopupDeleter.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupDeleter.o PopupDeleter.cpp + +${OBJECTDIR}/PopupUploader.o: PopupUploader.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupUploader.o PopupUploader.cpp + +${OBJECTDIR}/TransientMessageWidget.o: TransientMessageWidget.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/TransientMessageWidget.o TransientMessageWidget.cpp + +${OBJECTDIR}/main.o: main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -DLARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r ${CND_BUILDDIR}/${CND_CONF} + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git a/nbproject/Makefile-Debug.mk b/nbproject/Makefile-Debug.mk new file mode 100644 index 0000000..b21e215 --- /dev/null +++ b/nbproject/Makefile-Debug.mk @@ -0,0 +1,125 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +GREP=grep +NM=nm +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux +CND_DLIB_EXT=so +CND_CONF=Debug +CND_DISTDIR=dist +CND_BUILDDIR=build + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/AppConfig.o \ + ${OBJECTDIR}/GpgMECWorker.o \ + ${OBJECTDIR}/GpgMEWorker.o \ + ${OBJECTDIR}/K7Main.o \ + ${OBJECTDIR}/PopupDeleter.o \ + ${OBJECTDIR}/PopupUploader.o \ + ${OBJECTDIR}/TransientMessageWidget.o \ + ${OBJECTDIR}/main.o + + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-Wno-deprecated -Wno-deprecated-declarations +CXXFLAGS=-Wno-deprecated -Wno-deprecated-declarations + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS=-L/usr/local/Wt-Debug/lib -lwtd -lwthttpd -lgpgmepp -lgpgme + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 + +${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7: ${OBJECTFILES} + ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/AppConfig.o: AppConfig.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/AppConfig.o AppConfig.cpp + +${OBJECTDIR}/GpgMECWorker.o: GpgMECWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMECWorker.o GpgMECWorker.cpp + +${OBJECTDIR}/GpgMEWorker.o: GpgMEWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMEWorker.o GpgMEWorker.cpp + +${OBJECTDIR}/K7Main.o: K7Main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/K7Main.o K7Main.cpp + +${OBJECTDIR}/PopupDeleter.o: PopupDeleter.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupDeleter.o PopupDeleter.cpp + +${OBJECTDIR}/PopupUploader.o: PopupUploader.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupUploader.o PopupUploader.cpp + +${OBJECTDIR}/TransientMessageWidget.o: TransientMessageWidget.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/TransientMessageWidget.o TransientMessageWidget.cpp + +${OBJECTDIR}/main.o: main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -DDEVTIME -I/usr/local/Wt-Debug/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r ${CND_BUILDDIR}/${CND_CONF} + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git a/nbproject/Makefile-Release.mk b/nbproject/Makefile-Release.mk new file mode 100644 index 0000000..1293e5c --- /dev/null +++ b/nbproject/Makefile-Release.mk @@ -0,0 +1,125 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +GREP=grep +NM=nm +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux +CND_DLIB_EXT=so +CND_CONF=Release +CND_DISTDIR=dist +CND_BUILDDIR=build + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/AppConfig.o \ + ${OBJECTDIR}/GpgMECWorker.o \ + ${OBJECTDIR}/GpgMEWorker.o \ + ${OBJECTDIR}/K7Main.o \ + ${OBJECTDIR}/PopupDeleter.o \ + ${OBJECTDIR}/PopupUploader.o \ + ${OBJECTDIR}/TransientMessageWidget.o \ + ${OBJECTDIR}/main.o + + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-Wno-deprecated -Wno-deprecated-declarations +CXXFLAGS=-Wno-deprecated -Wno-deprecated-declarations + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS=-L/usr/local/Wt/lib -lwt -lwtfcgi -lgpgmepp -lgpgme + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 + +${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7: ${OBJECTFILES} + ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 ${OBJECTFILES} ${LDLIBSOPTIONS} -s + +${OBJECTDIR}/AppConfig.o: AppConfig.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/AppConfig.o AppConfig.cpp + +${OBJECTDIR}/GpgMECWorker.o: GpgMECWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMECWorker.o GpgMECWorker.cpp + +${OBJECTDIR}/GpgMEWorker.o: GpgMEWorker.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/GpgMEWorker.o GpgMEWorker.cpp + +${OBJECTDIR}/K7Main.o: K7Main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/K7Main.o K7Main.cpp + +${OBJECTDIR}/PopupDeleter.o: PopupDeleter.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupDeleter.o PopupDeleter.cpp + +${OBJECTDIR}/PopupUploader.o: PopupUploader.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/PopupUploader.o PopupUploader.cpp + +${OBJECTDIR}/TransientMessageWidget.o: TransientMessageWidget.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/TransientMessageWidget.o TransientMessageWidget.cpp + +${OBJECTDIR}/main.o: main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -s -I/usr/local/Wt/include -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r ${CND_BUILDDIR}/${CND_CONF} + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git a/nbproject/Makefile-impl.mk b/nbproject/Makefile-impl.mk new file mode 100644 index 0000000..68cd4d4 --- /dev/null +++ b/nbproject/Makefile-impl.mk @@ -0,0 +1,133 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a pre- and a post- target defined where you can add customization code. +# +# This makefile implements macros and targets common to all configurations. +# +# NOCDDL + + +# Building and Cleaning subprojects are done by default, but can be controlled with the SUB +# macro. If SUB=no, subprojects will not be built or cleaned. The following macro +# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf +# and .clean-reqprojects-conf unless SUB has the value 'no' +SUB_no=NO +SUBPROJECTS=${SUB_${SUB}} +BUILD_SUBPROJECTS_=.build-subprojects +BUILD_SUBPROJECTS_NO= +BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} +CLEAN_SUBPROJECTS_=.clean-subprojects +CLEAN_SUBPROJECTS_NO= +CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} + + +# Project Name +PROJECTNAME=K7 + +# Active Configuration +DEFAULTCONF=Debug +CONF=${DEFAULTCONF} + +# All Configurations +ALLCONFS=Debug Release ARM-Release + + +# build +.build-impl: .build-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf + + +# clean +.clean-impl: .clean-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf + + +# clobber +.clobber-impl: .clobber-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ + done + +# all +.all-impl: .all-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf; \ + done + +# build tests +.build-tests-impl: .build-impl .build-tests-pre + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-tests-conf + +# run tests +.test-impl: .build-tests-impl .test-pre + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .test-conf + +# dependency checking support +.depcheck-impl: + @echo "# This code depends on make tool being used" >.dep.inc + @if [ -n "${MAKE_VERSION}" ]; then \ + echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES} \$${TESTOBJECTFILES}))" >>.dep.inc; \ + echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ + echo "include \$${DEPFILES}" >>.dep.inc; \ + echo "endif" >>.dep.inc; \ + else \ + echo ".KEEP_STATE:" >>.dep.inc; \ + echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ + fi + +# configuration validation +.validate-impl: + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + echo ""; \ + echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ + echo "See 'make help' for details."; \ + echo "Current directory: " `pwd`; \ + echo ""; \ + fi + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + exit 1; \ + fi + + +# help +.help-impl: .help-pre + @echo "This makefile supports the following configurations:" + @echo " ${ALLCONFS}" + @echo "" + @echo "and the following targets:" + @echo " build (default target)" + @echo " clean" + @echo " clobber" + @echo " all" + @echo " help" + @echo "" + @echo "Makefile Usage:" + @echo " make [CONF=] [SUB=no] build" + @echo " make [CONF=] [SUB=no] clean" + @echo " make [SUB=no] clobber" + @echo " make [SUB=no] all" + @echo " make help" + @echo "" + @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," + @echo " also clean subprojects." + @echo "Target 'clobber' will remove all built files from all configurations and," + @echo " unless 'SUB=no', also from subprojects." + @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'help' prints this message." + @echo "" + diff --git a/nbproject/Makefile-variables.mk b/nbproject/Makefile-variables.mk new file mode 100644 index 0000000..19bf140 --- /dev/null +++ b/nbproject/Makefile-variables.mk @@ -0,0 +1,43 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +CND_BASEDIR=`pwd` +CND_BUILDDIR=build +CND_DISTDIR=dist +# Debug configuration +CND_PLATFORM_Debug=GNU-Linux +CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux +CND_ARTIFACT_NAME_Debug=k7 +CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/k7 +CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux/package +CND_PACKAGE_NAME_Debug=k7.tar +CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/k7.tar +# Release configuration +CND_PLATFORM_Release=GNU-Linux +CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux +CND_ARTIFACT_NAME_Release=k7 +CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/k7 +CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux/package +CND_PACKAGE_NAME_Release=k7.tar +CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/k7.tar +# ARM-Release configuration +CND_PLATFORM_ARM-Release=GNU-Linux +CND_ARTIFACT_DIR_ARM-Release=dist/ARM-Release/GNU-Linux +CND_ARTIFACT_NAME_ARM-Release=k7 +CND_ARTIFACT_PATH_ARM-Release=dist/ARM-Release/GNU-Linux/k7 +CND_PACKAGE_DIR_ARM-Release=dist/ARM-Release/GNU-Linux/package +CND_PACKAGE_NAME_ARM-Release=k7.tar +CND_PACKAGE_PATH_ARM-Release=dist/ARM-Release/GNU-Linux/package/k7.tar +# +# include compiler specific variables +# +# dmake command +ROOT:sh = test -f nbproject/private/Makefile-variables.mk || \ + (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk) +# +# gmake command +.PHONY: $(shell test -f nbproject/private/Makefile-variables.mk || (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk)) +# +include nbproject/private/Makefile-variables.mk diff --git a/nbproject/Package-ARM-Release.bash b/nbproject/Package-ARM-Release.bash new file mode 100644 index 0000000..6f944f8 --- /dev/null +++ b/nbproject/Package-ARM-Release.bash @@ -0,0 +1,76 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux +CND_CONF=ARM-Release +CND_DISTDIR=dist +CND_BUILDDIR=build +CND_DLIB_EXT=so +NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 +OUTPUT_BASENAME=k7 +PACKAGE_TOP_DIR=k7/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${NBTMPDIR} +mkdir -p ${NBTMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory "${NBTMPDIR}/k7/bin" +copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar +cd ${NBTMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${NBTMPDIR} diff --git a/nbproject/Package-Debug.bash b/nbproject/Package-Debug.bash new file mode 100644 index 0000000..a66a45a --- /dev/null +++ b/nbproject/Package-Debug.bash @@ -0,0 +1,76 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux +CND_CONF=Debug +CND_DISTDIR=dist +CND_BUILDDIR=build +CND_DLIB_EXT=so +NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 +OUTPUT_BASENAME=k7 +PACKAGE_TOP_DIR=k7/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${NBTMPDIR} +mkdir -p ${NBTMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory "${NBTMPDIR}/k7/bin" +copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar +cd ${NBTMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${NBTMPDIR} diff --git a/nbproject/Package-Release.bash b/nbproject/Package-Release.bash new file mode 100644 index 0000000..2dcd6aa --- /dev/null +++ b/nbproject/Package-Release.bash @@ -0,0 +1,76 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux +CND_CONF=Release +CND_DISTDIR=dist +CND_BUILDDIR=build +CND_DLIB_EXT=so +NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/k7 +OUTPUT_BASENAME=k7 +PACKAGE_TOP_DIR=k7/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${NBTMPDIR} +mkdir -p ${NBTMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory "${NBTMPDIR}/k7/bin" +copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar +cd ${NBTMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/k7.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${NBTMPDIR} diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml new file mode 100644 index 0000000..51be029 --- /dev/null +++ b/nbproject/configurations.xml @@ -0,0 +1,268 @@ + + + + + AppConfig.h + GpgMECWorker.h + GpgMEWorker.h + K7Main.h + PopupDeleter.h + PopupUploader.h + TransientMessageWidget.h + global.h + + + WTAPPROOT/K7/K7.xml + WTAPPROOT/K7/K7_fr.xml + + + AppConfig.cpp + GpgMECWorker.cpp + GpgMEWorker.cpp + K7Main.cpp + PopupDeleter.cpp + PopupUploader.cpp + TransientMessageWidget.cpp + main.cpp + + + + + Makefile + + + Makefile + + + + default + true + false + + + + + /usr/local/Wt-Debug/include + + -Wno-deprecated -Wno-deprecated-declarations + + DEVTIME + + + + + /usr/local/Wt-Debug/lib + + + wtd + wthttpd + gpgmepp + gpgme + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + true + false + + + + 5 + true + + + 5 + true + + /usr/local/Wt/include + + -Wno-deprecated -Wno-deprecated-declarations + + + 5 + + + 5 + + + + /usr/local/Wt/lib + + true + + wt + wtfcgi + gpgmepp + gpgme + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + true + false + + + + 5 + true + + + 5 + true + + /usr/local/Wt/include + + -Wno-deprecated -Wno-deprecated-declarations + + LARGEFILE_SOURCE=1 + _FILE_OFFSET_BITS=64 + + + + 5 + + + 5 + + + + /usr/local/Wt/lib + + true + + wt + wtfcgi + gpgmepp + gpgme + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nbproject/private/Makefile-variables.mk b/nbproject/private/Makefile-variables.mk new file mode 100644 index 0000000..2ed1418 --- /dev/null +++ b/nbproject/private/Makefile-variables.mk @@ -0,0 +1,8 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +# Debug configuration +# Release configuration +# ARM-Release configuration diff --git a/nbproject/private/c_standard_headers_indexer.c b/nbproject/private/c_standard_headers_indexer.c new file mode 100644 index 0000000..c2548d2 --- /dev/null +++ b/nbproject/private/c_standard_headers_indexer.c @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ + +// List of standard headers was taken in http://en.cppreference.com/w/c/header + +#include // Conditionally compiled macro that compares its argument to zero +#include // Functions to determine the type contained in character data +#include // Macros reporting error conditions +#include // Limits of float types +#include // Sizes of basic types +#include // Localization utilities +#include // Common mathematics functions +#include // Nonlocal jumps +#include // Signal handling +#include // Variable arguments +#include // Common macro definitions +#include // Input/output +#include // String handling +#include // General utilities: memory management, program utilities, string conversions, random numbers +#include // Time/date utilities +#include // (since C95) Alternative operator spellings +#include // (since C95) Extended multibyte and wide character utilities +#include // (since C95) Wide character classification and mapping utilities +#ifdef _STDC_C99 +#include // (since C99) Complex number arithmetic +#include // (since C99) Floating-point environment +#include // (since C99) Format conversion of integer types +#include // (since C99) Boolean type +#include // (since C99) Fixed-width integer types +#include // (since C99) Type-generic math (macros wrapping math.h and complex.h) +#endif +#ifdef _STDC_C11 +#include // (since C11) alignas and alignof convenience macros +#include // (since C11) Atomic types +#include // (since C11) noreturn convenience macros +#include // (since C11) Thread library +#include // (since C11) UTF-16 and UTF-32 character utilities +#endif diff --git a/nbproject/private/configurations.xml b/nbproject/private/configurations.xml new file mode 100644 index 0000000..c6b9916 --- /dev/null +++ b/nbproject/private/configurations.xml @@ -0,0 +1,114 @@ + + + Makefile + + + + localhost + 2 + + + + + + + + + + + + + + + gdb + + + + "${OUTPUT_PATH}" + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + true + 0 + 0 + + + + + + + + + localhost + 2 + + + + + + + + + + + + + + + gdb + + + + "${OUTPUT_PATH}" + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + true + 0 + 0 + + + + + + + + + localhost + 2 + + + + + + + + + + + + + + + gdb + + + + "${OUTPUT_PATH}" + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + "${OUTPUT_PATH}" --docroot . --https-address localhost --https-port 8080 --ssl-client-verification required --ssl-ca-certificates /home/user/tmp/ca.crt --ssl-certificate /home/user/tmp/cert.pem --ssl-private-key /home/user/tmp/cert.key --ssl-tmp-dh /home/user/tmp/dh.pem + + true + 0 + 0 + + + + + + + + diff --git a/nbproject/private/cpp_standard_headers_indexer.cpp b/nbproject/private/cpp_standard_headers_indexer.cpp new file mode 100644 index 0000000..04f6fa6 --- /dev/null +++ b/nbproject/private/cpp_standard_headers_indexer.cpp @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ + +// List of standard headers was taken in http://en.cppreference.com/w/cpp/header + +#include // General purpose utilities: program control, dynamic memory allocation, random numbers, sort and search +#include // Functions and macro constants for signal management +#include // Macro (and function) that saves (and jumps) to an execution context +#include // Handling of variable length argument lists +#include // Runtime type information utilities +#include // std::bitset class template +#include // Function objects, designed for use with the standard algorithms +#include // Various utility components +#include // C-style time/date utilites +#include // typedefs for types such as size_t, NULL and others +#include // Low-level memory management utilities +#include // Higher level memory management utilities +#include // limits of integral types +#include // limits of float types +#include // standardized way to query properties of arithmetic types +#include // Exception handling utilities +#include // Standard exception objects +#include // Conditionally compiled macro that compares its argument to zero +#include // Macro containing the last error number +#include // functions to determine the type contained in character data +#include // functions for determining the type of wide character data +#include // various narrow character string handling functions +#include // various wide and multibyte string handling functions +#include // std::basic_string class template +#include // std::vector container +#include // std::deque container +#include // std::list container +#include // std::set and std::multiset associative containers +#include // std::map and std::multimap associative containers +#include // std::stack container adaptor +#include // std::queue and std::priority_queue container adaptors +#include // Algorithms that operate on containers +#include // Container iterators +#include // Common mathematics functions +#include // Complex number type +#include // Class for representing and manipulating arrays of values +#include // Numeric operations on values in containers +#include // forward declarations of all classes in the input/output library +#include // std::ios_base class, std::basic_ios class template and several typedefs +#include // std::basic_istream class template and several typedefs +#include // std::basic_ostream, std::basic_iostream class templates and several typedefs +#include // several standard stream objects +#include // std::basic_fstream, std::basic_ifstream, std::basic_ofstream class templates and several typedefs +#include // std::basic_stringstream, std::basic_istringstream, std::basic_ostringstream class templates and several typedefs +#include // std::strstream, std::istrstream, std::ostrstream(deprecated) +#include // Helper functions to control the format or input and output +#include // std::basic_streambuf class template +#include // C-style input-output functions +#include // Localization utilities +#include // C localization utilities +#include // empty header. The macros that appear in iso646.h in C are keywords in C++ +#if __cplusplus >= 201103L +#include // (since C++11) std::type_index +#include // (since C++11) Compile-time type information +#include // (since C++11) C++ time utilites +#include // (since C++11) std::initializer_list class template +#include // (since C++11) std::tuple class template +#include // (since C++11) Nested allocator class +#include // (since C++11) fixed-size types and limits of other types +#include // (since C++11) formatting macros , intmax_t and uintmax_t math and conversions +#include // (since C++11) defines std::error_code, a platform-dependent error code +#include // (since C++11) C-style Unicode character conversion functions +#include // (since C++11) std::array container +#include // (since C++11) std::forward_list container +#include // (since C++11) std::unordered_set and std::unordered_multiset unordered associative containers +#include // (since C++11) std::unordered_map and std::unordered_multimap unordered associative containers +#include // (since C++11) Random number generators and distributions +#include // (since C++11) Compile-time rational arithmetic +#include // (since C++11) Floating-point environment access functions +#include // (since C++11) Unicode conversion facilities +#include // (since C++11) Classes, algorithms and iterators to support regular expression processing +#include // (since C++11) Atomic operations library +#include // (since C++11)(deprecated in C++17) simply includes the header +#include // (since C++11)(deprecated in C++17) simply includes the headers (until C++17) (since C++17) and : the overloads equivalent to the contents of the C header tgmath.h are already provided by those headers +#include // (since C++11)(deprecated in C++17) defines one compatibility macro constant +#include // (since C++11)(deprecated in C++17) defines one compatibility macro constant +#include // (since C++11) std::thread class and supporting functions +#include // (since C++11) mutual exclusion primitives +#include // (since C++11) primitives for asynchronous computations +#include // (since C++11) thread waiting conditions +#endif +#if __cplusplus >= 201300L +#include // (since C++14) shared mutual exclusion primitives +#endif +#if __cplusplus >= 201500L +#include // (since C++17) std::any class template +#include // (since C++17) std::optional class template +#include // (since C++17) std::variant class template +#include // (since C++17) Polymorphic allocators and memory resources +#include // (since C++17) std::basic_string_view class template +#include // (since C++17) Predefined execution policies for parallel versions of the algorithms +#include // (since C++17) std::path class and supporting functions +#endif diff --git a/nbproject/private/launcher.properties b/nbproject/private/launcher.properties new file mode 100644 index 0000000..3edc2d8 --- /dev/null +++ b/nbproject/private/launcher.properties @@ -0,0 +1,42 @@ +# Launchers File syntax: +# +# [Must-have property line] +# launcher1.runCommand= +# [Optional extra properties] +# launcher1.displayName= +# launcher1.hide= +# launcher1.buildCommand= +# launcher1.runDir= +# launcher1.runInOwnTab= +# launcher1.symbolFiles= +# launcher1.env.= +# (If this value is quoted with ` it is handled as a native command which execution result will become the value) +# [Common launcher properties] +# common.runDir= +# (This value is overwritten by a launcher specific runDir value if the latter exists) +# common.env.= +# (Environment variables from common launcher are merged with launcher specific variables) +# common.symbolFiles= +# (This value is overwritten by a launcher specific symbolFiles value if the latter exists) +# +# In runDir, symbolFiles and env fields you can use these macroses: +# ${PROJECT_DIR} - project directory absolute path +# ${OUTPUT_PATH} - linker output path (relative to project directory path) +# ${OUTPUT_BASENAME}- linker output filename +# ${TESTDIR} - test files directory (relative to project directory path) +# ${OBJECTDIR} - object files directory (relative to project directory path) +# ${CND_DISTDIR} - distribution directory (relative to project directory path) +# ${CND_BUILDDIR} - build directory (relative to project directory path) +# ${CND_PLATFORM} - platform name +# ${CND_CONF} - configuration name +# ${CND_DLIB_EXT} - dynamic library extension +# +# All the project launchers must be listed in the file! +# +# launcher1.runCommand=... +# launcher2.runCommand=... +# ... +# common.runDir=... +# common.env.KEY=VALUE + +# launcher1.runCommand= \ No newline at end of file diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml new file mode 100644 index 0000000..ca16eb4 --- /dev/null +++ b/nbproject/private/private.xml @@ -0,0 +1,15 @@ + + + + 1 + 0 + + + + + file:/home/user/tmp/cpp/WTProjects/K7/main.cpp + file:/home/user/tmp/cpp/WTProjects/K7/K7Main.h + file:/home/user/tmp/cpp/WTProjects/K7/K7Main.cpp + + + diff --git a/nbproject/project.xml b/nbproject/project.xml new file mode 100644 index 0000000..8103df2 --- /dev/null +++ b/nbproject/project.xml @@ -0,0 +1,35 @@ + + + org.netbeans.modules.cnd.makeproject + + + K7 + + cpp + h + UTF-8 + + + + + Debug + 1 + + + Release + 1 + + + ARM-Release + 1 + + + + true + ANSI|ANSI + ANSI|ANSI + ANSI|ANSI + + + + diff --git a/resources b/resources new file mode 120000 index 0000000..00dac7e --- /dev/null +++ b/resources @@ -0,0 +1 @@ +/usr/local/Wt/share/Wt/resources \ No newline at end of file