diff --git a/skeema/gradido_login/hedera_topics.sql b/skeema/gradido_login/hedera_topics.sql index 02f7e3b39..b9adaefc2 100644 --- a/skeema/gradido_login/hedera_topics.sql +++ b/skeema/gradido_login/hedera_topics.sql @@ -1,6 +1,7 @@ CREATE TABLE `hedera_topics` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `topic_hedera_id` int unsigned NOT NULL, + `name` VARCHAR(255) NOT NULL DEFAULT '', `auto_renew_account_hedera_id` int unsigned DEFAULT NULL, `auto_renew_period` int unsigned NOT NULL DEFAULT '0', `group_id` int unsigned NOT NULL, diff --git a/src/cpp/Crypto/KeyPairHedera.cpp b/src/cpp/Crypto/KeyPairHedera.cpp index 27d9731a7..62643cc99 100644 --- a/src/cpp/Crypto/KeyPairHedera.cpp +++ b/src/cpp/Crypto/KeyPairHedera.cpp @@ -10,7 +10,7 @@ KeyPairHedera::KeyPairHedera() } -KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const unsigned char* publicKey/* = nullptr*/, size_t publicKeySize/* = 0*/) +KeyPairHedera::KeyPairHedera(const unsigned char* privateKey, size_t privateKeySize, const unsigned char* publicKey/* = nullptr*/, size_t publicKeySize/* = 0*/) : mPrivateKey(nullptr) { auto derPrefixPriv = DataTypeConverter::hexToBin("302e020100300506032b657004220420"); @@ -19,27 +19,28 @@ KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const unsigned char* p auto mm = MemoryManager::getInstance(); if (privateKey) { - switch (privateKey->size()) { + switch (privateKeySize) { case 48: // key with prefix - if (0 == sodium_memcmp(*privateKey, *derPrefixPriv, derPrefixPriv->size())) { + if (0 == sodium_memcmp(privateKey, *derPrefixPriv, derPrefixPriv->size())) { //int crypto_sign_seed_keypair(unsigned char *pk, unsigned char *sk, const unsigned char *seed); auto seed = mm->getFreeMemory(crypto_sign_ed25519_SEEDBYTES); - memcpy(*seed, privateKey->data(derPrefixPriv->size()), crypto_sign_ed25519_SEEDBYTES); - createKeyFromSeed(seed); + memcpy(*seed, &privateKey[derPrefixPriv->size()], crypto_sign_ed25519_SEEDBYTES); + createKeyFromSeed(seed->data(), seed->size()); + mm->releaseMemory(seed); break; } case 32: - createKeyFromSeed(privateKey); + createKeyFromSeed(privateKey, privateKeySize); break; case 64: //mPrivateKey = privateKey; - if (!mPrivateKey || mPrivateKey->size() != privateKey->size()) { + if (!mPrivateKey || mPrivateKey->size() != privateKeySize) { if (mPrivateKey) { mm->releaseMemory(mPrivateKey); } - mPrivateKey = mm->getFreeMemory(privateKey->size()); - memcpy(*mPrivateKey, *privateKey, privateKey->size()); + mPrivateKey = mm->getFreeMemory(privateKeySize); + memcpy(*mPrivateKey, privateKey, privateKeySize); } break; default: @@ -75,11 +76,17 @@ KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const unsigned char* p mm->releaseMemory(derPrefixPub); } KeyPairHedera::KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey /* = nullptr*/) - : KeyPairHedera(privateKey, publicKey->data(), publicKey->size()) + : KeyPairHedera(privateKey->data(), privateKey->size(), publicKey->data(), publicKey->size()) { } +KeyPairHedera::KeyPairHedera(const std::vector& privateKey, const unsigned char* publicKey/* = nullptr*/, size_t publicKeySize/* = 0*/) + : KeyPairHedera(privateKey.data(), privateKey.size(), publicKey, publicKeySize) +{ + +} + KeyPairHedera::~KeyPairHedera() { auto mm = MemoryManager::getInstance(); @@ -90,13 +97,13 @@ KeyPairHedera::~KeyPairHedera() } -void KeyPairHedera::createKeyFromSeed(const MemoryBin* seed) +void KeyPairHedera::createKeyFromSeed(const unsigned char* seed, size_t seedSize) { - assert(seed && seed->size() == crypto_sign_ed25519_SEEDBYTES); + assert(seed && seedSize == crypto_sign_ed25519_SEEDBYTES); auto mm = MemoryManager::getInstance(); auto secret_key = mm->getFreeMemory(crypto_sign_SECRETKEYBYTES); - crypto_sign_seed_keypair(mPublicKey, *secret_key, *seed); + crypto_sign_seed_keypair(mPublicKey, *secret_key, seed); if (mPrivateKey) { mm->releaseMemory(mPrivateKey); @@ -177,6 +184,15 @@ MemoryBin* KeyPairHedera::getCryptedPrivKey(const Poco::AutoPtrgetFreeMemory(mPrivateKey->size()); + memcpy(*private_key_copy, *mPrivateKey, mPrivateKey->size()); + return private_key_copy; +} + MemoryBin* KeyPairHedera::getPublicKeyCopy() const { auto mm = MemoryManager::getInstance(); diff --git a/src/cpp/Crypto/KeyPairHedera.h b/src/cpp/Crypto/KeyPairHedera.h index a3e4337e5..b308cbe9e 100644 --- a/src/cpp/Crypto/KeyPairHedera.h +++ b/src/cpp/Crypto/KeyPairHedera.h @@ -22,8 +22,9 @@ public: //! \param privateKey: copy //! \param publicKey: copy //! - KeyPairHedera(const MemoryBin* privateKey, const unsigned char* publicKey = nullptr, size_t publicKeySize = 0); + KeyPairHedera(const unsigned char* privateKey, size_t privateKeySize, const unsigned char* publicKey = nullptr, size_t publicKeySize = 0); KeyPairHedera(const MemoryBin* privateKey, const MemoryBin* publicKey = nullptr); + KeyPairHedera(const std::vector& privateKey, const unsigned char* publicKey = nullptr, size_t publicKeySize = 0); ~KeyPairHedera(); @@ -64,13 +65,14 @@ public: inline bool hasPrivateKey() const { return mPrivateKey != nullptr; } - //! \brief only way to get a private key.. encrypted + //! \brief MemoryBin* getCryptedPrivKey(const Poco::AutoPtr password) const; + MemoryBin* getPrivateKeyCopy() const; protected: KeyPairHedera(); - void createKeyFromSeed(const MemoryBin* seed); + void createKeyFromSeed(const unsigned char* seed, size_t seedSize); private: diff --git a/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp b/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp index fa99a7b35..54a416bef 100644 --- a/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp +++ b/src/cpp/HTTPInterface/AdminHederaAccountPage.cpp @@ -70,7 +70,7 @@ void AdminHederaAccountPage::handleRequest(Poco::Net::HTTPServerRequest& request addError(new Error("Action Update Balance", "hedera id not found")); } else { hedera_time.reset(); - hedera_account[0]->updateBalanceFromHedera(user, this); + hedera_account[0]->hederaAccountGetBalance(user, this); addNotification(new ParamSuccess("Hedera", "crypto get balance success in ", hedera_time.string())); } } @@ -318,7 +318,8 @@ void AdminHederaAccountPage::handleRequest(Poco::Net::HTTPServerRequest& request #line 206 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminHederaAccount.cpsp" responseStream << ( gettext("Add Account") ); responseStream << "\">\n"; - responseStream << "\t\n"; + responseStream << "\t\t\n"; + responseStream << "\t\n"; responseStream << "\n"; // begin include footer.cpsp responseStream << "
\n"; diff --git a/src/cpp/HTTPInterface/AdminTopicPage.cpp b/src/cpp/HTTPInterface/AdminTopicPage.cpp index d8926093e..66fb252d7 100644 --- a/src/cpp/HTTPInterface/AdminTopicPage.cpp +++ b/src/cpp/HTTPInterface/AdminTopicPage.cpp @@ -7,8 +7,10 @@ #line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" - -#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" + #include "../controller/HederaAccount.h" + #include "../controller/Group.h" + #include "../ServerConfig.h" +#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" #include "../ServerConfig.h" @@ -27,20 +29,34 @@ void AdminTopicPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: if (_compressResponse) response.set("Content-Encoding", "gzip"); Poco::Net::HTMLForm form(request, request.stream()); -#line 10 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" +#line 12 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" const char* pageName = "Topic"; + auto user = mSession->getNewUser(); + + int auto_renew_period = 604800; // 7 Tage + int auto_renew_account = 0; + int group_id = 0; + + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } - -#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" +#line 3 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" bool withMaterialIcons = false; std::ostream& _responseStream = response.send(); Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1); std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream; responseStream << "\n"; - // begin include header_large.cpsp + // begin include header.cpsp responseStream << "\n"; responseStream << "\n"; responseStream << "\n"; @@ -48,57 +64,132 @@ void AdminTopicPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << "\n"; responseStream << "\n"; responseStream << "Gradido Login Server: "; -#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" +#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" responseStream << ( pageName ); responseStream << "\n"; responseStream << "\n"; -#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" +#line 13 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" if(withMaterialIcons) { responseStream << "\n"; responseStream << "\n"; -#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_large.cpsp" +#line 15 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header.cpsp" } responseStream << "\n"; responseStream << "\n"; responseStream << "\n"; responseStream << "
\n"; - responseStream << "\t\t
\n"; - responseStream << "\t\t\t
\n"; - responseStream << "\t\t\t\t\n"; - responseStream << "\t\t\t
\n"; - responseStream << "\t\t
\n"; - responseStream << "\t\t
"; - // end include header_large.cpsp + responseStream << "
\n"; + responseStream << " "; + // end include header.cpsp responseStream << "\n"; -#line 16 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" + responseStream << "\n"; +#line 40 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminTopic.cpsp" responseStream << ( getErrorsHtml() ); responseStream << "\n"; responseStream << "
\n"; responseStream << "\t

Topic Admin Page

\n"; responseStream << "
\n"; - responseStream << "
\n"; - responseStream << "\t\n"; + responseStream << "
\n"; + responseStream << "\t
\n"; + responseStream << "\t

Ein neues Topic anlegen

\n"; + responseStream << "\t
\n"; + responseStream << "\t
\n"; + responseStream << "\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t
\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\t\n"; + responseStream << "\t\t\n"; + responseStream << "\t
\n"; responseStream << "
\n"; // begin include footer.cpsp responseStream << "
\n"; @@ -124,5 +215,18 @@ void AdminTopicPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco:: responseStream << ""; // end include footer.cpsp responseStream << "\n"; + responseStream << "\n"; + responseStream << ""; if (_compressResponse) _gzipStream.close(); } diff --git a/src/cpp/controller/CryptoKey.cpp b/src/cpp/controller/CryptoKey.cpp index 79d68a62e..aa8df1b8d 100644 --- a/src/cpp/controller/CryptoKey.cpp +++ b/src/cpp/controller/CryptoKey.cpp @@ -15,16 +15,25 @@ namespace controller { } - Poco::AutoPtr CryptoKey::create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user) + Poco::AutoPtr CryptoKey::create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user, bool saveEncrypted/* = true*/) { auto mm = MemoryManager::getInstance(); - auto encrypted_priv_key = hederaKeyPair->getCryptedPrivKey(user->getPassword()); + MemoryBin* private_key = nullptr; auto public_key = hederaKeyPair->getPublicKeyCopy(); - auto db = new model::table::CryptoKey(encrypted_priv_key, public_key, model::table::KEY_TYPE_ED25519_HEDERA); + model::table::KeyType key_type; + if (saveEncrypted) { + key_type = model::table::KEY_TYPE_ED25519_HEDERA_ENCRYPTED; + private_key = hederaKeyPair->getCryptedPrivKey(user->getPassword()); + } + else { + key_type = model::table::KEY_TYPE_ED25519_HEDERA_CLEAR; + private_key = hederaKeyPair->getPrivateKeyCopy(); + } + auto db = new model::table::CryptoKey(private_key, public_key, key_type); - mm->releaseMemory(encrypted_priv_key); + mm->releaseMemory(private_key); mm->releaseMemory(public_key); auto cryptoKey = new CryptoKey(db); @@ -63,28 +72,49 @@ namespace controller { return nullptr; } - std::unique_ptr CryptoKey::getKeyPair(Poco::AutoPtr user) + std::unique_ptr CryptoKey::getKeyPair(Poco::AutoPtr user) const { auto model = getModel(); - auto password = user->getPassword(); - auto mm = MemoryManager::getInstance(); - if (!password || !model->hasPrivateKeyEncrypted()) { - printf("[CryptoKey::getKeyPair] return null, password empty or no private key\n"); + assert(model); + + if (!model->isEncrypted()) { + return getKeyPair(); + } + + if (!model->hasPrivateKey()) { + printf("[CryptoKey::getKeyPair] return null, no private key\n"); return nullptr; } - MemoryBin* clearPassword = nullptr; - auto encrypted_private_key = model->getPrivateKeyEncrypted(); - auto encrypted_private_key_hex_string = DataTypeConverter::binToHex(encrypted_private_key); - printf("[CryptoKey::getKeyPair] encrypted private key hex: %s\n", encrypted_private_key_hex_string.data()); - if (password->decrypt(model->getPrivateKeyEncrypted(), &clearPassword) != SecretKeyCryptography::AUTH_DECRYPT_OK) { + + auto password = user->getPassword(); + auto mm = MemoryManager::getInstance(); + if (!password) { + printf("[CryptoKey::getKeyPair] return null, password empty\n"); + } + MemoryBin* clearPrivateKey = nullptr; + auto encrypted_private_key = model->getPrivateKey(); + //auto encrypted_private_key_hex_string = DataTypeConverter::binToHex(encrypted_private_key); + //printf("[CryptoKey::getKeyPair] encrypted private key hex: %s\n", encrypted_private_key_hex_string.data()); + if (password->decrypt(model->getPrivateKey(), &clearPrivateKey) != SecretKeyCryptography::AUTH_DECRYPT_OK) { printf("[CryptoKey::getKeyPair] return null, error decrypting\n"); return nullptr; } - auto key_pair = std::make_unique(clearPassword, model->getPublicKey(), model->getPublicKeySize()); - mm->releaseMemory(clearPassword); + auto key_pair = std::make_unique(clearPrivateKey->data(), clearPrivateKey->size(), model->getPublicKey(), model->getPublicKeySize()); + mm->releaseMemory(clearPrivateKey); return key_pair; } + std::unique_ptr CryptoKey::getKeyPair() const + { + auto model = getModel(); + assert(model); + if (!model->hasPrivateKey() || model->isEncrypted()) { + printf("[CryptoKey::getKeyPair] no private key or encrypted\n"); + return nullptr; + } + + return std::make_unique(model->getPrivateKey(), model->getPublicKey(), model->getPublicKeySize()); + } } diff --git a/src/cpp/controller/CryptoKey.h b/src/cpp/controller/CryptoKey.h index fc69d042c..ef48c88f1 100644 --- a/src/cpp/controller/CryptoKey.h +++ b/src/cpp/controller/CryptoKey.h @@ -16,7 +16,7 @@ namespace controller { ~CryptoKey(); - static Poco::AutoPtr create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user); + static Poco::AutoPtr create(const KeyPairHedera* hederaKeyPair, Poco::AutoPtr user, bool saveEncrypted = true); //! if returned ptr is NULL, dataset not found static Poco::AutoPtr load(int id); @@ -26,8 +26,10 @@ namespace controller { inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } inline Poco::AutoPtr getModel() { return _getModel(); } + inline const model::table::CryptoKey* getModel() const { return _getModel(); } - std::unique_ptr getKeyPair(Poco::AutoPtr user); + std::unique_ptr getKeyPair(Poco::AutoPtr user) const; + std::unique_ptr getKeyPair() const; protected: diff --git a/src/cpp/controller/HederaAccount.cpp b/src/cpp/controller/HederaAccount.cpp index 6fabe2848..e4873ecf0 100644 --- a/src/cpp/controller/HederaAccount.cpp +++ b/src/cpp/controller/HederaAccount.cpp @@ -73,7 +73,7 @@ namespace controller { return resultVector; } - bool HederaAccount::updateBalanceFromHedera(Poco::AutoPtr user, NotificationList* errorReceiver/* = nullptr*/) + bool HederaAccount::hederaAccountGetBalance(Poco::AutoPtr user, NotificationList* errorReceiver/* = nullptr*/) { static const char* functionName = "HederaAccount::updateBalanceFromHedera"; @@ -132,5 +132,15 @@ namespace controller { return false; } + + std::string HederaAccount::toShortSelectOptionName() + { + std::stringstream ss; + auto model = getModel(); + ss << model::table::HederaAccount::hederaNetworkTypeToString((model::table::HederaNetworkType)model->getNetworkType()) << " "; + ss << mHederaID->getModel()->toString() << " " << ((double)model->getBalance() / 100000000.0) << " Hbar"; + return ss.str(); + } + } diff --git a/src/cpp/controller/HederaAccount.h b/src/cpp/controller/HederaAccount.h index d76420b78..a9a53d528 100644 --- a/src/cpp/controller/HederaAccount.h +++ b/src/cpp/controller/HederaAccount.h @@ -22,12 +22,14 @@ namespace controller { inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + std::string HederaAccount::toShortSelectOptionName(); + inline Poco::AutoPtr getModel() { return _getModel(); } inline void setHederaId(Poco::AutoPtr hederaId) { mHederaID = hederaId; } inline Poco::AutoPtr getHederaId() { return mHederaID; } - bool updateBalanceFromHedera(Poco::AutoPtr user, NotificationList* errorReceiver = nullptr); + bool hederaAccountGetBalance(Poco::AutoPtr user, NotificationList* errorReceiver = nullptr); protected: HederaAccount(model::table::HederaAccount* dbModel); diff --git a/src/cpp/controller/HederaRequest.cpp b/src/cpp/controller/HederaRequest.cpp index 308ffa5e8..64998fa6a 100644 --- a/src/cpp/controller/HederaRequest.cpp +++ b/src/cpp/controller/HederaRequest.cpp @@ -59,6 +59,18 @@ HederaRequestReturn HederaRequest::request(model::hedera::Query* query, model::h return HEDERA_REQUEST_RETURN_OK; } +HederaRequestReturn HederaRequest::request(model::hedera::Transaction* transaction, model::hedera::Response* response) +{ + auto channel = grpc::CreateChannel(transaction->getConnectionString(), grpc::InsecureChannelCredentials()); + + grpc::ClientContext context; + std::chrono::system_clock::time_point deadline = std::chrono::system_clock::now() + + std::chrono::milliseconds(5000); + context.set_deadline(deadline); + + return HEDERA_REQUEST_RETURN_OK; +} + #include "Poco/JSON/Object.h" #include "../lib/JsonRequest.h" diff --git a/src/cpp/controller/HederaRequest.h b/src/cpp/controller/HederaRequest.h index 327ee7634..34bd304a1 100644 --- a/src/cpp/controller/HederaRequest.h +++ b/src/cpp/controller/HederaRequest.h @@ -31,6 +31,7 @@ public: ~HederaRequest(); HederaRequestReturn request(model::hedera::Query* query, model::hedera::Response* response, Poco::UInt64 fee = 0); + HederaRequestReturn request(model::hedera::Transaction* transaction, model::hedera::Response* response); //! for testing, didn't work server say invalid json :/ HederaRequestReturn requestViaPHPRelay(model::hedera::Query* query); diff --git a/src/cpp/controller/HederaTopic.cpp b/src/cpp/controller/HederaTopic.cpp new file mode 100644 index 000000000..3885c31d8 --- /dev/null +++ b/src/cpp/controller/HederaTopic.cpp @@ -0,0 +1,26 @@ +#include "HederaTopic.h" +#include "../model/hedera/Transaction.h" + +namespace controller { + HederaTopic::HederaTopic(model::table::HederaTopic* dbModel) + { + mDBModel = dbModel; + } + HederaTopic::~HederaTopic() + { + + } + + Poco::AutoPtr HederaTopic::create(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId) + { + auto db = new model::table::HederaTopic(name, autoRenewAccountId, autoRenewPeriod, groupId); + + auto hedera_topic = new HederaTopic(db); + return Poco::AutoPtr(hedera_topic); + } + + Poco::UInt64 HederaTopic::hederaCreateTopic() + { + + } +} \ No newline at end of file diff --git a/src/cpp/controller/HederaTopic.h b/src/cpp/controller/HederaTopic.h new file mode 100644 index 000000000..de5552e39 --- /dev/null +++ b/src/cpp/controller/HederaTopic.h @@ -0,0 +1,38 @@ +#ifndef __GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H +#define __GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H + +/*! +* +* \author: Dario Rekowski +* +* \date: 03.09.2020 +* +* \brief: Class for Hedera Topic, connct db table with hedera object +* +*/ +#include "TableControllerBase.h" +#include "../model/table/HederaTopic.h" + +namespace controller { + class HederaTopic : public TableControllerBase + { + public: + + ~HederaTopic(); + + static Poco::AutoPtr create(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId); + + //! \brief hedera call to create a hedera topic + Poco::UInt64 hederaCreateTopic(); + + inline bool deleteFromDB() { return mDBModel->deleteFromDB(); } + + inline Poco::AutoPtr getModel() { return _getModel(); } + + + protected: + HederaTopic(model::table::HederaTopic* dbModel); + + }; + +#endif //__GRADIDO_LOGIN_SERVER_CONTROLLER_HEDERA_TOPIC_H \ No newline at end of file diff --git a/src/cpp/main.cpp b/src/cpp/main.cpp index 910db09ff..899779fef 100644 --- a/src/cpp/main.cpp +++ b/src/cpp/main.cpp @@ -45,17 +45,25 @@ int main(int argc, char** argv) printf("[Gradido_LoginServer::main] error loading mnemonic Word List"); return -2; } + printf("[Gradido_LoginServer::main] mnemonic word lists loaded!\n"); if (!ImportantTests::passphraseGenerationAndTransformation()) { printf("test passphrase generation and transformation failed\n"); return -3; } + printf("[Gradido_LoginServer::main] passed important tests\n"); grpc_init(); Gradido_LoginServer app; - auto result = app.run(argc, argv); - - grpc_shutdown(); - return result; + try { + auto result = app.run(argc, argv); + grpc_shutdown(); + return result; + } + catch (Poco::Exception& ex) { + printf("[Gradido_LoginServer::main] exception by starting server: %s\n", ex.displayText().data()); + } + return -1; + } #endif \ No newline at end of file diff --git a/src/cpp/model/hedera/ConsensusCreateTopic.cpp b/src/cpp/model/hedera/ConsensusCreateTopic.cpp index e69de29bb..6ca423102 100644 --- a/src/cpp/model/hedera/ConsensusCreateTopic.cpp +++ b/src/cpp/model/hedera/ConsensusCreateTopic.cpp @@ -0,0 +1,45 @@ +#include "ConsensusCreateTopic.h" + +namespace model { + namespace hedera { + ConsensusCreateTopic::ConsensusCreateTopic(Poco::AutoPtr autoRenewHederaAccountId, Poco::UInt32 autoRenewPeriod) + : mProtoCreateTopic(nullptr) + { + mProtoCreateTopic = new proto::ConsensusCreateTopicTransactionBody; + auto auto_renew_period = mProtoCreateTopic->mutable_autorenewperiod(); + auto_renew_period->set_seconds(autoRenewPeriod); + + auto auto_renew_account = mProtoCreateTopic->mutable_autorenewaccount(); + autoRenewHederaAccountId->copyToProtoAccountId(auto_renew_account); + + } + ConsensusCreateTopic::~ConsensusCreateTopic() + { + if (mProtoCreateTopic) { + delete mProtoCreateTopic; + mProtoCreateTopic = nullptr; + } + } + + void ConsensusCreateTopic::setAdminKey(const MemoryBin* adminPublicKey) + { + auto admin_key = mProtoCreateTopic->mutable_adminkey(); + auto admin_key_string = admin_key->mutable_ed25519(); + *admin_key_string = std::string((const char)*adminPublicKey, adminPublicKey->size()); + } + void ConsensusCreateTopic::setSubmitKey(const MemoryBin* submitPublicKey) + { + auto submit_key = mProtoCreateTopic->mutable_submitkey(); + auto submit_key_string = submit_key->mutable_ed25519(); + *submit_key_string = std::string((const char)*submitPublicKey, submitPublicKey->size()); + } + + bool ConsensusCreateTopic::validate() + { + if (mProtoCreateTopic->autorenewperiod().seconds() > 86400 && 0 != mProtoCreateTopic->autorenewaccount().accountnum()) { + return true; + } + return false; + } + } +} \ No newline at end of file diff --git a/src/cpp/model/hedera/ConsensusCreateTopic.h b/src/cpp/model/hedera/ConsensusCreateTopic.h index e69de29bb..e61da46f3 100644 --- a/src/cpp/model/hedera/ConsensusCreateTopic.h +++ b/src/cpp/model/hedera/ConsensusCreateTopic.h @@ -0,0 +1,31 @@ +#ifndef __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H +#define __GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H + +#include "../../proto/hedera/ConsensusCreateTopic.pb.h" +#include "../../SingletonManager/MemoryManager.h" + +#include "../../controller/HederaId.h" + +namespace model { + namespace hedera { + class ConsensusCreateTopic + { + public: + ConsensusCreateTopic(Poco::AutoPtr autoRenewHederaAccountId, Poco::UInt32 autoRenewPeriod); + ~ConsensusCreateTopic(); + + inline void setMemo(const std::string& memo) { mProtoCreateTopic->set_memo(memo); } + void setAdminKey(const MemoryBin* adminPublicKey); + void setSubmitKey(const MemoryBin* submitPublicKey); + + bool validate(); + + inline proto::ConsensusCreateTopicTransactionBody* getProtoTransactionBody() { return mProtoCreateTopic; } + inline void resetPointer() { mProtoCreateTopic = nullptr; } + protected: + proto::ConsensusCreateTopicTransactionBody* mProtoCreateTopic; + }; + } +} + +#endif //__GRADIDO_LOGIN_SERVER_MODEL_HEDERA_CONSENSUS_CREATE_TOPIC_H \ No newline at end of file diff --git a/src/cpp/model/hedera/CryptoCreateTransaction.cpp b/src/cpp/model/hedera/CryptoCreateTransaction.cpp new file mode 100644 index 000000000..696a8d6e7 --- /dev/null +++ b/src/cpp/model/hedera/CryptoCreateTransaction.cpp @@ -0,0 +1,16 @@ +#include "CryptoCreateTransaction.h" + +namespace model { + namespace hedera { + + CryptoCreateTransaction::CryptoCreateTransaction() + { + } + + CryptoCreateTransaction::~CryptoCreateTransaction() + { + + } + + } +} \ No newline at end of file diff --git a/src/cpp/model/hedera/CryptoCreateTransaction.h b/src/cpp/model/hedera/CryptoCreateTransaction.h new file mode 100644 index 000000000..e1425ebf5 --- /dev/null +++ b/src/cpp/model/hedera/CryptoCreateTransaction.h @@ -0,0 +1,23 @@ +#ifndef __GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H +#define __GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H + +#include "../../proto/hedera/CryptoCreate.pb.h" + +namespace model { + namespace hedera { + + class CryptoCreateTransaction + { + public: + CryptoCreateTransaction(); + ~CryptoCreateTransaction(); + + protected: + proto::CryptoCreateTransactionBody* mCryptoCreateBody; + }; + } +} + + + +#endif //__GRADIDO_LOGIN_MODEL_HEDERA_CRYPTO_CREATE_TRANSACTION_H \ No newline at end of file diff --git a/src/cpp/model/hedera/Query.cpp b/src/cpp/model/hedera/Query.cpp index de4fdec99..11a8eb735 100644 --- a/src/cpp/model/hedera/Query.cpp +++ b/src/cpp/model/hedera/Query.cpp @@ -9,8 +9,8 @@ namespace model { namespace hedera { - Query::Query(const controller::NodeServerConnection& connection) - : mConnection(connection), mTransactionBody(nullptr) + Query::Query() + : mTransactionBody(nullptr) { } @@ -27,7 +27,7 @@ namespace model { assert(!accountId.isNull() && accountId->getModel()); - auto query = new Query(connection); + auto query = new Query; auto get_account_balance = query->mQueryProto.mutable_cryptogetaccountbalance(); accountId->copyToProtoAccountId(get_account_balance->mutable_accountid()); auto query_header = get_account_balance->mutable_header(); diff --git a/src/cpp/model/hedera/Query.h b/src/cpp/model/hedera/Query.h index fa9b06471..376528314 100644 --- a/src/cpp/model/hedera/Query.h +++ b/src/cpp/model/hedera/Query.h @@ -26,15 +26,14 @@ namespace model { void setResponseType(proto::ResponseType type); proto::ResponseType getResponseType(); - void setFee(Poco::UInt64 fee); + inline const proto::Query* getProtoQuery() const { return &mQueryProto; } - inline std::string getConnectionString() const { return mConnection.getUriWithPort(); } + inline std::string getConnectionString() const { return mTransactionBody->getConnectionString(); } protected: - Query(const controller::NodeServerConnection& connection); + Query(); proto::Query mQueryProto; TransactionBody* mTransactionBody; - controller::NodeServerConnection mConnection; }; } } diff --git a/src/cpp/model/hedera/Transaction.cpp b/src/cpp/model/hedera/Transaction.cpp index 0dadbcb4c..4699e71ea 100644 --- a/src/cpp/model/hedera/Transaction.cpp +++ b/src/cpp/model/hedera/Transaction.cpp @@ -19,6 +19,7 @@ namespace model { bool Transaction::sign(std::unique_ptr keyPairHedera, const TransactionBody* transactionBody) { auto mm = MemoryManager::getInstance(); + mConnection = transactionBody->getConnection(); auto transaction_body_proto = transactionBody->getProtoTransactionBody(); auto body_bytes = transaction_body_proto->SerializeAsString(); mTransaction->set_bodybytes(body_bytes.data()); diff --git a/src/cpp/model/hedera/Transaction.h b/src/cpp/model/hedera/Transaction.h index 3acf46ff9..d5e9434bd 100644 --- a/src/cpp/model/hedera/Transaction.h +++ b/src/cpp/model/hedera/Transaction.h @@ -25,11 +25,12 @@ namespace model { bool sign(std::unique_ptr keyPairHedera, const TransactionBody* transactionBody); inline proto::Transaction* getTransaction() { return mTransaction; } + inline std::string getConnectionString() const { return mConnection.getUriWithPort(); } void resetPointer() { mTransaction = nullptr; } protected: - proto::Transaction* mTransaction; + controller::NodeServerConnection mConnection; }; } } diff --git a/src/cpp/model/hedera/TransactionBody.cpp b/src/cpp/model/hedera/TransactionBody.cpp index f1979b6bf..f215ada23 100644 --- a/src/cpp/model/hedera/TransactionBody.cpp +++ b/src/cpp/model/hedera/TransactionBody.cpp @@ -3,6 +3,7 @@ namespace model { namespace hedera { TransactionBody::TransactionBody(Poco::AutoPtr operatorAccountId, const controller::NodeServerConnection& connection) + : mConnection(connection) { connection.hederaId->copyToProtoAccountId(mTransactionBody.mutable_nodeaccountid()); auto transaction_id = mTransactionBody.mutable_transactionid(); @@ -29,10 +30,24 @@ namespace model { return false; } + bool TransactionBody::setCreateTopic(ConsensusCreateTopic& consensusCreateTopicTransaction) + { + if (consensusCreateTopicTransaction.validate()) { + mTransactionBody.set_allocated_consensuscreatetopic(consensusCreateTopicTransaction.getProtoTransactionBody()); + consensusCreateTopicTransaction.resetPointer(); + return true; + } + return false; + } + void TransactionBody::setMemo(const std::string& memo) { mTransactionBody.set_memo(memo); } + void TransactionBody::setFee(Poco::UInt64 fee) + { + mTransactionBody.set_transactionfee(fee); + } void TransactionBody::updateTimestamp() { diff --git a/src/cpp/model/hedera/TransactionBody.h b/src/cpp/model/hedera/TransactionBody.h index 3663c4a59..ba421e014 100644 --- a/src/cpp/model/hedera/TransactionBody.h +++ b/src/cpp/model/hedera/TransactionBody.h @@ -13,6 +13,7 @@ #include "../../proto/hedera/TransactionBody.pb.h" #include "../../controller/NodeServer.h" #include "CryptoTransferTransaction.h" +#include "ConsensusCreateTopic.h" namespace model { namespace hedera { @@ -23,14 +24,20 @@ namespace model { ~TransactionBody(); void setMemo(const std::string& memo); - + void setFee(Poco::UInt64 fee); + bool setCryptoTransfer(CryptoTransferTransaction& cryptoTransferTransaction); + bool setCreateTopic(ConsensusCreateTopic& consensusCreateTopicTransaction); + //bool inline const proto::TransactionBody* getProtoTransactionBody() const { return &mTransactionBody; } + inline std::string getConnectionString() const { return mConnection.getUriWithPort(); } + inline controller::NodeServerConnection getConnection() const { return mConnection; } protected: void updateTimestamp(); proto::TransactionBody mTransactionBody; + controller::NodeServerConnection mConnection; }; } } diff --git a/src/cpp/model/table/CryptoKey.cpp b/src/cpp/model/table/CryptoKey.cpp index 9588f57e7..a4f1034e3 100644 --- a/src/cpp/model/table/CryptoKey.cpp +++ b/src/cpp/model/table/CryptoKey.cpp @@ -43,12 +43,33 @@ namespace model { const char* CryptoKey::typeToString(KeyType type) { switch (type) { - case KEY_TYPE_ED25519_SODIUM: return "ed25519 ref10"; - case KEY_TYPE_ED25519_HEDERA: return "sodium ed22519"; + case KEY_TYPE_ED25519_SODIUM_ENCRYPTED: return "ed25519 sodium encrypted"; + case KEY_TYPE_ED25519_HEDERA_ENCRYPTED: return "ed22519 for hedera encrypted"; + case KEY_TYPE_ED25519_SODIUM_CLEAR: return "ed25519 sodium clear"; + case KEY_TYPE_ED25519_HEDERA_CLEAR: return "ed25519 hedera clear"; } return ""; } + bool CryptoKey::hasPrivateKeyEncrypted() const + { + const KeyType type = (KeyType)(mKeyType); + if (type == KEY_TYPE_ED25519_HEDERA_ENCRYPTED || type == KEY_TYPE_ED25519_SODIUM_ENCRYPTED) { + return !mPrivateKey.isNull(); + } + return false; + } + + bool CryptoKey::isEncrypted() const + { + const KeyType type = (KeyType)(mKeyType); + if (type == KEY_TYPE_ED25519_HEDERA_ENCRYPTED || + type == KEY_TYPE_ED25519_SODIUM_ENCRYPTED) { + return true; + } + return false; + } + Poco::Data::Statement CryptoKey::_loadFromDB(Poco::Data::Session session, const std::string& fieldName) { Poco::Data::Statement select(session); diff --git a/src/cpp/model/table/CryptoKey.h b/src/cpp/model/table/CryptoKey.h index 7e50fc728..c1fa0b66d 100644 --- a/src/cpp/model/table/CryptoKey.h +++ b/src/cpp/model/table/CryptoKey.h @@ -8,8 +8,10 @@ namespace model { namespace table { enum KeyType { - KEY_TYPE_ED25519_SODIUM = 0, - KEY_TYPE_ED25519_HEDERA = 1, + KEY_TYPE_ED25519_SODIUM_ENCRYPTED = 0, + KEY_TYPE_ED25519_HEDERA_ENCRYPTED = 1, + KEY_TYPE_ED25519_SODIUM_CLEAR = 2, + KEY_TYPE_ED25519_HEDERA_CLEAR = 3, KEY_TYPE_COUNT }; @@ -27,8 +29,10 @@ namespace model { inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } size_t getPublicKeySize() const { if (mPublicKey.isNull()) return 0; return mPublicKey.value().content().size(); } - inline bool hasPrivateKeyEncrypted() const { return !mPrivateKey.isNull(); } - inline const std::vector& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); } + bool hasPrivateKeyEncrypted() const; + bool isEncrypted() const; + inline bool hasPrivateKey() const { return !mPrivateKey.isNull(); } + inline const std::vector& getPrivateKey() const { return mPrivateKey.value().content(); } static const char* typeToString(KeyType type); protected: diff --git a/src/cpp/model/table/HederaAccount.cpp b/src/cpp/model/table/HederaAccount.cpp index 1485ff554..2479c09cc 100644 --- a/src/cpp/model/table/HederaAccount.cpp +++ b/src/cpp/model/table/HederaAccount.cpp @@ -44,6 +44,7 @@ namespace model { return ss.str(); } + const char* HederaAccount::hederaNetworkTypeToString(HederaNetworkType type) { switch (type) { diff --git a/src/cpp/model/table/HederaAccount.h b/src/cpp/model/table/HederaAccount.h index 4d4dd6575..6b0d636a0 100644 --- a/src/cpp/model/table/HederaAccount.h +++ b/src/cpp/model/table/HederaAccount.h @@ -28,6 +28,7 @@ namespace model { // generic db operations const char* getTableName() const { return "hedera_accounts"; } std::string toString(); + static const char* hederaNetworkTypeToString(HederaNetworkType type); static NodeServerType networkTypeToNodeServerType(HederaNetworkType type); diff --git a/src/cpp/model/table/HederaTopic.cpp b/src/cpp/model/table/HederaTopic.cpp index ef80ea071..b91ea0864 100644 --- a/src/cpp/model/table/HederaTopic.cpp +++ b/src/cpp/model/table/HederaTopic.cpp @@ -5,6 +5,14 @@ using namespace Poco::Data::Keywords; namespace model { namespace table { HederaTopic::HederaTopic() + : mTopicHederaId(0), mAutoRenewAccountHederaId(0), mAutoRenewPeriod(0), mGroupId(0), mAdminKeyId(0), mSubmitKeyId(0),mSequenceNumber(0) + { + + } + + HederaTopic::HederaTopic(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId) + : mTopicHederaId(0), mName(name), mAutoRenewAccountHederaId(autoRenewAccountId), mAutoRenewPeriod(autoRenewAccountId), mGroupId(groupId), + mAdminKeyId(0), mSubmitKeyId(0), mSequenceNumber(0) { } @@ -18,6 +26,7 @@ namespace model { { std::stringstream ss; ss << "Topic Hedera id: " << std::to_string(mTopicHederaId) << std::endl; + ss << "Name: " << mName << std::endl; ss << "Auto Renew Account Hedera id: " << std::to_string(mAutoRenewAccountHederaId) << std::endl; ss << "Auto Renew Period: " << std::to_string(mAutoRenewPeriod) << " seconds" << std::endl; ss << "Group id: " << std::to_string(mGroupId) << std::endl; @@ -33,10 +42,10 @@ namespace model { { Poco::Data::Statement select(session); - select << "SELECT id, topic_hedera_id, auto_renew_account_hedera_id, auto_renew_period, " + select << "SELECT id, topic_hedera_id, name, auto_renew_account_hedera_id, auto_renew_period, " << "group_id, admin_key_id, submit_key_id, current_timeout, sequence_number, updated FROM " << getTableName() << " where " << fieldName << " = ?" - , into(mID), into(mTopicHederaId), into(mAutoRenewAccountHederaId), into(mAutoRenewPeriod) + , into(mID), into(mTopicHederaId), into(mName), into(mAutoRenewAccountHederaId), into(mAutoRenewPeriod) , into(mGroupId), into(mAdminKeyId), into(mSubmitKeyId), into(mCurrentTimeout), into(mSequenceNumber), into(mUpdated); return select; @@ -57,9 +66,9 @@ namespace model { Poco::Data::Statement insert(session); lock(); insert << "INSERT INTO " << getTableName() - << " (topic_hedera_id, auto_renew_account_hedera_id, auto_renew_period," + << " (topic_hedera_id, name, auto_renew_account_hedera_id, auto_renew_period," << " group_id, admin_key_id, submit_key_id, current_timeout, sequence_number) VALUES(?,?,?,?,?,?,?,?)" - , use(mTopicHederaId), use(mAutoRenewAccountHederaId), use(mAutoRenewPeriod) + , use(mTopicHederaId), use(mName), use(mAutoRenewAccountHederaId), use(mAutoRenewPeriod) , use(mGroupId), use(mAdminKeyId), use(mSubmitKeyId), use(mCurrentTimeout), use(mSequenceNumber), use(mUpdated); unlock(); return insert; diff --git a/src/cpp/model/table/HederaTopic.h b/src/cpp/model/table/HederaTopic.h index fe5cc342b..3c8cb6f16 100644 --- a/src/cpp/model/table/HederaTopic.h +++ b/src/cpp/model/table/HederaTopic.h @@ -10,12 +10,25 @@ namespace model { { public: HederaTopic(); + HederaTopic(const std::string& name, int autoRenewAccountId, int autoRenewPeriod, int groupId); ~HederaTopic(); // generic db operations const char* getTableName() const { return "hedera_topics"; } std::string toString(); + inline Poco::UInt32 getTopicHederaId() const { return mTopicHederaId; } + inline std::string getName() const { return mName; } + inline Poco::UInt32 getAutoRenewAccountId() const { return mAutoRenewAccountHederaId; } + inline Poco::UInt32 getAutoRenewPeriod() const { return mAutoRenewPeriod; } + inline Poco::UInt32 getGroupId() const { return mGroupId;} + inline Poco::DateTime getCurrentTimoout() const { return mCurrentTimeout; } + inline Poco::UInt64 getSequenceNumber() const { return mSequenceNumber; } + inline Poco::DateTime getUpdated() const { return mUpdated; } + + inline void setTopicHederaID(Poco::UInt32 topidHederaId) { mTopicHederaId = topidHederaId;} + inline void setSequeceNumber(Poco::UInt64 sequenceNumber) { mSequenceNumber = sequenceNumber; } + inline void setCurrentTimeout(Poco::DateTime currentTimeOut) { mCurrentTimeout = currentTimeOut; } protected: Poco::Data::Statement _loadFromDB(Poco::Data::Session session, const std::string& fieldName); @@ -23,6 +36,7 @@ namespace model { Poco::Data::Statement _insertIntoDB(Poco::Data::Session session); Poco::UInt32 mTopicHederaId; + std::string mName; Poco::UInt32 mAutoRenewAccountHederaId; // in seconds Poco::UInt32 mAutoRenewPeriod; diff --git a/src/cpsp/adminHederaAccount.cpsp b/src/cpsp/adminHederaAccount.cpsp index 3e8795d24..95d6992b7 100644 --- a/src/cpsp/adminHederaAccount.cpsp +++ b/src/cpsp/adminHederaAccount.cpsp @@ -49,7 +49,7 @@ addError(new Error("Action Update Balance", "hedera id not found")); } else { hedera_time.reset(); - hedera_account[0]->updateBalanceFromHedera(user, this); + hedera_account[0]->hederaAccountGetBalance(user, this); addNotification(new ParamSuccess("Hedera", "crypto get balance success in ", hedera_time.string())); } } @@ -204,6 +204,7 @@ <% } %> "> - + +
<%@ include file="footer.cpsp" %> diff --git a/src/cpsp/adminTopic.cpsp b/src/cpsp/adminTopic.cpsp index 3eac5a976..ffef4ea18 100644 --- a/src/cpsp/adminTopic.cpsp +++ b/src/cpsp/adminTopic.cpsp @@ -5,19 +5,123 @@ <%@ page ctorArg="Session*" %> <%@ header include="SessionHTTPRequestHandler.h" %> <%! - + #include "../controller/HederaAccount.h" + #include "../controller/Group.h" + #include "../SingletonManager/SessionManager.h" + #include "../ServerConfig.h" + #include "../lib/DataTypeConverter.h" %> <%% const char* pageName = "Topic"; + auto user = mSession->getNewUser(); + auto sm = SessionManager::getInstance(); + + std::string name = ""; + int auto_renew_account = 0; + int auto_renew_period = 604800; // 7 Tage + + int group_id = 0; + if(!form.empty()) { + name = form.get("topic-name", ""); + auto auto_renew_account_string = form.get("topic-auto-renew-account", "0"); + auto auto_renew_period_string = form.get("topic-auto-renew-period", "604800"); + auto group_id_string = form.get("topic-group", "-1"); + + if(name != "" && !sm->isValid(name, VALIDATE_NAME)) { + addError(new Error("Topic", "Name not valid, at least 3 Character")); + } + + if(!sm->isValid(auto_renew_account_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew account id not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_account_string, auto_renew_account) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew account id to int")); + } + } + + if(!sm->isValid(auto_renew_period_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "auto renew period not an integer")); + } else { + if(DataTypeConverter::strToInt(auto_renew_period_string, auto_renew_period) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting auto renew period to int")); + } + } -%><%@ include file="header_large.cpsp" %> + if(!sm->isValid(group_id_string, VALIDATE_ONLY_INTEGER)) { + addError(new Error("Topic", "group_id not an integer")); + } else { + if(DataTypeConverter::strToInt(group_id_string, group_id) != DataTypeConverter::NUMBER_PARSE_OKAY) { + addError(new Error("Int convert error", "Error converting group_id to int")); + } + } + } + + + auto hedera_accounts = controller::HederaAccount::load("user_id", user->getModel()->getID()); + + auto groups = controller::Group::listAll(); + std::map group_indices; + int count = 0; + for(auto it = groups.begin(); it != groups.end(); it++) { + group_indices.insert(std::pair((*it)->getModel()->getID(), count)); + count++; + } + + +%><%@ include file="header.cpsp" %> + <%= getErrorsHtml() %>

Topic Admin Page

-
- +
+
+

Ein neues Topic anlegen

+
+
+
+ + + + + +
+ + + + "> + +
<%@ include file="footer.cpsp" %> + + \ No newline at end of file