chore(CPP): Enhance type safety using phantom types
Important changes: - Converted the easy to mix strings to named types as phantom types - Renamed `AccountDto`s to `MultiAccount` to better match the status-go domain knowledge. - Renamed MultiAccount to ChatOrWalletAccount to better match its multi purpose and don't confuse with the MultiAccount domain knowledge. - Remove libs/CMakeLists.txt Note: Tried to use the fluent::NamedType but it doesn't work with nlohmann_json, gave up finding why. Therefore I extracted only the needed functionality for the simple types we use. Updates: #6321
This commit is contained in:
parent
a130681dd5
commit
16b866ccbd
|
@ -8,6 +8,7 @@ noBackup/
|
|||
*.log
|
||||
.update.timestamp
|
||||
.vscode
|
||||
*.code-workspace
|
||||
.tours
|
||||
bin/
|
||||
/bottles/
|
||||
|
|
|
@ -27,9 +27,18 @@ endif()
|
|||
|
||||
# status-desktop application
|
||||
add_subdirectory(vendor)
|
||||
add_subdirectory(libs)
|
||||
|
||||
add_subdirectory(libs/ApplicationCore)
|
||||
add_subdirectory(libs/Assets)
|
||||
add_subdirectory(libs/Helpers)
|
||||
add_subdirectory(libs/Onboarding)
|
||||
add_subdirectory(libs/StatusGoQt)
|
||||
add_subdirectory(libs/StatusQ)
|
||||
|
||||
add_subdirectory(app)
|
||||
|
||||
add_subdirectory(test/libs/StatusGoQt)
|
||||
|
||||
# TODO: temporary not to duplicate resources until we switch to c++ app then it can be refactored
|
||||
add_subdirectory(resources)
|
||||
add_subdirectory(ui/imports/assets)
|
||||
|
|
|
@ -32,6 +32,9 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
qml/Status/Application/MainShortcuts.qml
|
||||
qml/Status/Application/StatusWindow.qml
|
||||
|
||||
SOURCES
|
||||
res/app.qrc
|
||||
|
||||
OUTPUT_DIRECTORY
|
||||
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/Application
|
||||
)
|
||||
|
@ -47,7 +50,6 @@ target_compile_definitions(${PROJECT_NAME} PRIVATE BUILD_SOURCE_DIR=${CMAKE_SOUR
|
|||
|
||||
add_subdirectory(qml/Status/Application/Navigation)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(res)
|
||||
|
||||
include(${CMAKE_SOURCE_DIR}/cmake/platform_specific.cmake)
|
||||
string(TOLOWER ${PROJECT_ORGANIZATION_NAME} URL_ORGANIZATION_NAME)
|
||||
|
|
|
@ -14,7 +14,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Application.Navigation
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
StatusNavigationBar.qml
|
||||
StatusNavigationButton.qml
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
# TODO workaround until Qt6 API is clarified
|
||||
target_sources(${PROJECT_NAME}
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/app.qrc
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
|
||||
)
|
||||
|
||||
# TODO find out why it isn't working
|
||||
#
|
||||
#qt6_target_qml_sources(${PROJECT_NAME}
|
||||
# RESOURCES
|
||||
# qtquickcontrols2.conf
|
||||
# PREFIX ""
|
||||
#)
|
|
@ -20,7 +20,6 @@ qt6_add_qml_module(Assets
|
|||
URI Status.Assets
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
qml/Status/Assets/Resources.qml
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
add_subdirectory(ApplicationCore)
|
||||
add_subdirectory(Assets)
|
||||
add_subdirectory(Helpers)
|
||||
add_subdirectory(Onboarding)
|
||||
add_subdirectory(StatusGoQt)
|
||||
add_subdirectory(StatusQ)
|
|
@ -71,5 +71,6 @@ target_sources(Helpers
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/src/Helpers/helpers.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Helpers/logs.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Helpers/logs.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Helpers/NamedType.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Helpers/Singleton.h
|
||||
)
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::Helpers {
|
||||
|
||||
template<typename T>
|
||||
using IsNotReference = typename std::enable_if<!std::is_reference<T>::value, void>::type;
|
||||
|
||||
/// Featureless version of https://github.com/joboccara/NamedType that works with nlohmann::json
|
||||
template <typename T, typename Parameter>
|
||||
class NamedType
|
||||
{
|
||||
public:
|
||||
using UnderlyingType = T;
|
||||
|
||||
// constructor
|
||||
explicit constexpr NamedType(T const& value) : m_value(value) {}
|
||||
template<typename T_ = T, typename = IsNotReference<T_>>
|
||||
explicit constexpr NamedType(T&& value) : m_value(std::move(value)) {}
|
||||
explicit constexpr NamedType() = default;
|
||||
|
||||
// get
|
||||
constexpr T& get() { return m_value; }
|
||||
constexpr std::remove_reference_t<T> const& get() const {return m_value; }
|
||||
|
||||
bool operator<(const NamedType<T, Parameter> &) const = default;
|
||||
bool operator>(const NamedType<T, Parameter> &) const = default;
|
||||
bool operator<=(const NamedType<T, Parameter> &) const = default;
|
||||
bool operator>=(const NamedType<T, Parameter> &) const = default;
|
||||
bool operator==(const NamedType<T, Parameter> &) const = default;
|
||||
bool operator!=(const NamedType<T, Parameter> &) const = default;
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
template <typename T, typename P>
|
||||
void to_json(json& j, const NamedType<T, P>& p) {
|
||||
j = p.get();
|
||||
}
|
||||
|
||||
template <typename T, typename P>
|
||||
void from_json(const json& j, NamedType<T, P>& p) {
|
||||
p = NamedType<T, P>{j.get<T>()};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template <typename T, typename Parameter>
|
||||
struct hash<Status::Helpers::NamedType<T, Parameter>>
|
||||
{
|
||||
using NamedType = Status::Helpers::NamedType<T, Parameter>;
|
||||
using checkIfHashable = typename std::enable_if<NamedType::is_hashable, void>::type;
|
||||
|
||||
size_t operator()(NamedType const& x) const
|
||||
{
|
||||
return std::hash<T>()(x.get());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -4,13 +4,8 @@ namespace fs = std::filesystem;
|
|||
|
||||
namespace Status {
|
||||
|
||||
QString toQString(const std::string &str)
|
||||
{
|
||||
return QString::fromStdString(str);
|
||||
}
|
||||
|
||||
QString toQString(const fs::path &path) {
|
||||
return toQString(path.string());
|
||||
return QString::fromStdString(path.string());
|
||||
}
|
||||
|
||||
fs::path toPath(const QString &pathStr) {
|
||||
|
|
|
@ -12,8 +12,8 @@ using json = nlohmann::json;
|
|||
|
||||
namespace Status {
|
||||
|
||||
QString toQString(const std::string& str);
|
||||
QString toQString(const std::filesystem::path& path);
|
||||
|
||||
std::filesystem::path toPath(const QString& pathStr);
|
||||
|
||||
} // namespace Status
|
||||
|
@ -42,4 +42,15 @@ struct adl_serializer<QColor> {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct adl_serializer<std::optional<T>> {
|
||||
static void to_json(json& j, const std::optional<T>& opt) {
|
||||
j = opt.value();
|
||||
}
|
||||
|
||||
static void from_json(const json& j, std::optional<T>& opt) {
|
||||
opt.emplace(j.get<T>());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nlohmann
|
||||
|
|
|
@ -37,6 +37,9 @@ add_subdirectory(src)
|
|||
add_subdirectory(tests)
|
||||
|
||||
target_link_libraries(Onboarding
|
||||
PUBLIC
|
||||
Status::StatusGoQt
|
||||
|
||||
PRIVATE
|
||||
Qt6::Quick
|
||||
Qt6::Qml
|
||||
|
@ -45,7 +48,6 @@ target_link_libraries(Onboarding
|
|||
Status::ApplicationCore
|
||||
Status::Helpers
|
||||
|
||||
Status::StatusGoQt
|
||||
Status::StatusGoConfig
|
||||
)
|
||||
|
||||
|
|
|
@ -11,9 +11,6 @@ SetupNewProfilePageBase {
|
|||
TempTextInput {
|
||||
id: confirmPasswordInput
|
||||
|
||||
// TODO: remove this developer helper
|
||||
text: qsTr("1234567890")
|
||||
|
||||
width: 416
|
||||
height: 44
|
||||
|
||||
|
|
|
@ -26,12 +26,12 @@ getDataFromFile(const fs::path &path)
|
|||
return data;
|
||||
}
|
||||
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
namespace StatusGo = Status::StatusGo;
|
||||
namespace Utils = Status::StatusGo::Utils;
|
||||
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
AccountsService::AccountsService()
|
||||
: m_isFirstTimeAccountLogin(false)
|
||||
{
|
||||
|
@ -49,32 +49,32 @@ bool AccountsService::init(const fs::path& statusgoDataDir)
|
|||
|
||||
for(const auto &genAddressObj : response.result)
|
||||
{
|
||||
auto gAcc = GeneratedAccountDto::toGeneratedAccountDto(genAddressObj.toObject());
|
||||
auto gAcc = GeneratedMultiAccount::toGeneratedMultiAccount(genAddressObj.toObject());
|
||||
gAcc.alias = generateAlias(gAcc.derivedAccounts.whisper.publicKey);
|
||||
m_generatedAccounts.push_back(std::move(gAcc));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<AccountDto> AccountsService::openAndListAccounts()
|
||||
std::vector<MultiAccount> AccountsService::openAndListAccounts()
|
||||
{
|
||||
auto response = StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str());
|
||||
if(response.containsError())
|
||||
{
|
||||
qWarning() << response.error.message;
|
||||
return std::vector<AccountDto>();
|
||||
return std::vector<MultiAccount>();
|
||||
}
|
||||
|
||||
const auto multiAccounts = response.result;
|
||||
std::vector<AccountDto> result;
|
||||
std::vector<MultiAccount> result;
|
||||
for(const auto &value : multiAccounts)
|
||||
{
|
||||
result.push_back(AccountDto::toAccountDto(value.toObject()));
|
||||
result.push_back(MultiAccount::toMultiAccount(value.toObject()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<GeneratedAccountDto>& AccountsService::generatedAccounts() const
|
||||
const std::vector<GeneratedMultiAccount>& AccountsService::generatedAccounts() const
|
||||
{
|
||||
return m_generatedAccounts;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ bool AccountsService::setupAccountAndLogin(const QString &accountId, const QStri
|
|||
QJsonObject settings(getAccountSettings(accountId, installationId, displayName));
|
||||
QJsonObject nodeConfig(getDefaultNodeConfig(installationId));
|
||||
|
||||
QString hashedPassword(Utils::hashString(password));
|
||||
auto hashedPassword(Utils::hashPassword(password));
|
||||
|
||||
// This initialize the DB if first time running. Required for storing accounts
|
||||
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError())
|
||||
|
@ -105,12 +105,12 @@ bool AccountsService::setupAccountAndLogin(const QString &accountId, const QStri
|
|||
return getLoggedInAccount().isValid();
|
||||
}
|
||||
|
||||
const AccountDto& AccountsService::getLoggedInAccount() const
|
||||
const MultiAccount& AccountsService::getLoggedInAccount() const
|
||||
{
|
||||
return m_loggedInAccount;
|
||||
}
|
||||
|
||||
const GeneratedAccountDto& AccountsService::getImportedAccount() const
|
||||
const GeneratedMultiAccount& AccountsService::getImportedAccount() const
|
||||
{
|
||||
return m_importedAccount;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ bool AccountsService::setKeyStoreDir(const QString &key)
|
|||
return !response.containsError();
|
||||
}
|
||||
|
||||
QString AccountsService::login(AccountDto account, const QString& password)
|
||||
QString AccountsService::login(MultiAccount account, const QString& password)
|
||||
{
|
||||
// This is a requirement. Make it more explicit into the status go module
|
||||
if(!setKeyStoreDir(account.keyUid))
|
||||
|
@ -137,7 +137,7 @@ QString AccountsService::login(AccountDto account, const QString& password)
|
|||
if(StatusGo::Accounts::openAccounts(m_statusgoDataDir.c_str()).containsError())
|
||||
return QString("Failed to open accounts before logging in");
|
||||
|
||||
QString hashedPassword(Utils::hashString(password));
|
||||
auto hashedPassword(Utils::hashPassword(password));
|
||||
|
||||
QString thumbnailImage;
|
||||
QString largeImage;
|
||||
|
@ -157,8 +157,8 @@ QString AccountsService::login(AccountDto account, const QString& password)
|
|||
void AccountsService::clear()
|
||||
{
|
||||
m_generatedAccounts.clear();
|
||||
m_loggedInAccount = AccountDto();
|
||||
m_importedAccount = GeneratedAccountDto();
|
||||
m_loggedInAccount = MultiAccount();
|
||||
m_importedAccount = GeneratedMultiAccount();
|
||||
m_isFirstTimeAccountLogin = false;
|
||||
}
|
||||
|
||||
|
@ -174,15 +174,15 @@ QString AccountsService::generateAlias(const QString& publicKey)
|
|||
return response.result;
|
||||
}
|
||||
|
||||
void AccountsService::deleteMultiAccount(const AccountDto &account)
|
||||
void AccountsService::deleteMultiAccount(const MultiAccount &account)
|
||||
{
|
||||
StatusGo::Accounts::deleteMultiaccount(account.keyUid, m_keyStoreDir);
|
||||
}
|
||||
|
||||
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId, const QString& hashedPassword,
|
||||
const QVector<QString>& paths)
|
||||
DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath> &paths)
|
||||
{
|
||||
auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, hashedPassword, paths);
|
||||
auto response = StatusGo::Accounts::storeDerivedAccounts(accountId, password, paths);
|
||||
if(response.containsError())
|
||||
{
|
||||
qWarning() << response.error.message;
|
||||
|
@ -191,31 +191,31 @@ DerivedAccounts AccountsService::storeDerivedAccounts(const QString& accountId,
|
|||
return DerivedAccounts::toDerivedAccounts(response.result);
|
||||
}
|
||||
|
||||
StoredAccountDto AccountsService::storeAccount(const QString& accountId, const QString& hashedPassword)
|
||||
StoredMultiAccount AccountsService::storeAccount(const QString& accountId, const StatusGo::HashedPassword& password)
|
||||
{
|
||||
auto response = StatusGo::Accounts::storeAccount(accountId, hashedPassword);
|
||||
auto response = StatusGo::Accounts::storeAccount(accountId, password);
|
||||
if(response.containsError())
|
||||
{
|
||||
qWarning() << response.error.message;
|
||||
return StoredAccountDto();
|
||||
return StoredMultiAccount();
|
||||
}
|
||||
return toStoredAccountDto(response.result);
|
||||
return toStoredMultiAccount(response.result);
|
||||
}
|
||||
|
||||
AccountDto AccountsService::saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
MultiAccount AccountsService::saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& config)
|
||||
{
|
||||
if(!StatusGo::Accounts::saveAccountAndLogin(hashedPassword, account, subaccounts, settings, config)) {
|
||||
if(!StatusGo::Accounts::saveAccountAndLogin(password, account, subaccounts, settings, config)) {
|
||||
qWarning() << "Failed saving acccount" << account.value("name");
|
||||
return AccountDto();
|
||||
return MultiAccount();
|
||||
}
|
||||
|
||||
m_isFirstTimeAccountLogin = true;
|
||||
return AccountDto::toAccountDto(account);
|
||||
return MultiAccount::toMultiAccount(account);
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedAccountDto& account, const QString &displayName) const
|
||||
QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const
|
||||
{
|
||||
return QJsonObject{{"name", displayName.isEmpty() ? account.alias : displayName},
|
||||
{"address", account.address},
|
||||
|
@ -225,7 +225,7 @@ QJsonObject AccountsService::prepareAccountJsonObject(const GeneratedAccountDto&
|
|||
|
||||
QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId, const QString &displayName) const
|
||||
{
|
||||
for(const GeneratedAccountDto &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
{
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
@ -245,7 +245,7 @@ QJsonObject AccountsService::getAccountDataForAccountId(const QString &accountId
|
|||
return QJsonObject();
|
||||
}
|
||||
|
||||
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedAccountDto& account, const QString &displayName) const
|
||||
QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedMultiAccount& account, const QString &displayName) const
|
||||
{
|
||||
return {
|
||||
QJsonObject{
|
||||
|
@ -253,7 +253,7 @@ QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedAccountDt
|
|||
{"address", account.derivedAccounts.defaultWallet.address},
|
||||
{"color", "#4360df"},
|
||||
{"wallet", true},
|
||||
{"path", Constants::General::PathDefaultWallet},
|
||||
{"path", Constants::General::PathDefaultWallet.get()},
|
||||
{"name", "Status account"},
|
||||
{"derived-from", account.address}
|
||||
},
|
||||
|
@ -261,7 +261,7 @@ QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedAccountDt
|
|||
{"public-key", account.derivedAccounts.whisper.publicKey},
|
||||
{"address", account.derivedAccounts.whisper.address},
|
||||
{"name", displayName.isEmpty() ? account.alias : displayName},
|
||||
{"path", Constants::General::PathWhisper},
|
||||
{"path", Constants::General::PathWhisper.get()},
|
||||
{"chat", true},
|
||||
{"derived-from", ""}
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ QJsonArray AccountsService::prepareSubaccountJsonObject(const GeneratedAccountDt
|
|||
QJsonArray AccountsService::getSubaccountDataForAccountId(const QString& accountId, const QString &displayName) const
|
||||
{
|
||||
// "All these for loops with a nested if cry for a std::find_if :)"
|
||||
for(const GeneratedAccountDto &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
{
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
@ -302,7 +302,7 @@ QString AccountsService::generateSigningPhrase(int count) const
|
|||
return words.join(" ");
|
||||
}
|
||||
|
||||
QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedAccountDto& account,
|
||||
QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedMultiAccount& account,
|
||||
const QString& installationId,
|
||||
const QString& displayName) const
|
||||
{
|
||||
|
@ -348,7 +348,7 @@ QJsonObject AccountsService::prepareAccountSettingsJsonObject(const GeneratedAcc
|
|||
|
||||
QJsonObject AccountsService::getAccountSettings(const QString& accountId, const QString& installationId, const QString &displayName) const
|
||||
{
|
||||
for(const GeneratedAccountDto &acc : m_generatedAccounts)
|
||||
for(const GeneratedMultiAccount &acc : m_generatedAccounts)
|
||||
|
||||
if(acc.id == accountId)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusGo/Types.h>
|
||||
|
||||
#include "AccountsServiceInterface.h"
|
||||
|
||||
namespace Status::Onboarding
|
||||
|
@ -25,18 +27,18 @@ public:
|
|||
bool init(const fs::path& statusgoDataDir) override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
[[nodiscard]] std::vector<AccountDto> openAndListAccounts() override;
|
||||
[[nodiscard]] std::vector<MultiAccount> openAndListAccounts() override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
[[nodiscard]] const std::vector<GeneratedAccountDto>& generatedAccounts() const override;
|
||||
[[nodiscard]] const std::vector<GeneratedMultiAccount>& generatedAccounts() const override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
bool setupAccountAndLogin(const QString& accountId, const QString& password, const QString& displayName) override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
[[nodiscard]] const AccountDto& getLoggedInAccount() const override;
|
||||
[[nodiscard]] const MultiAccount& getLoggedInAccount() const override;
|
||||
|
||||
[[nodiscard]] const GeneratedAccountDto& getImportedAccount() const override;
|
||||
[[nodiscard]] const GeneratedMultiAccount& getImportedAccount() const override;
|
||||
|
||||
/// \see ServiceInterface
|
||||
[[nodiscard]] bool isFirstTimeAccountLogin() const override;
|
||||
|
@ -44,34 +46,34 @@ public:
|
|||
/// \see ServiceInterface
|
||||
bool setKeyStoreDir(const QString &key) override;
|
||||
|
||||
QString login(AccountDto account, const QString& password) override;
|
||||
QString login(MultiAccount account, const QString& password) override;
|
||||
|
||||
void clear() override;
|
||||
|
||||
QString generateAlias(const QString& publicKey) override;
|
||||
|
||||
void deleteMultiAccount(const AccountDto &account) override;
|
||||
void deleteMultiAccount(const MultiAccount &account) override;
|
||||
|
||||
private:
|
||||
QJsonObject prepareAccountJsonObject(const GeneratedAccountDto& account, const QString& displayName) const;
|
||||
QJsonObject prepareAccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const;
|
||||
|
||||
DerivedAccounts storeDerivedAccounts(const QString& accountId, const QString& hashedPassword,
|
||||
const QVector<QString>& paths);
|
||||
StoredAccountDto storeAccount(const QString& accountId, const QString& hashedPassword);
|
||||
DerivedAccounts storeDerivedAccounts(const QString& accountId, const StatusGo::HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths);
|
||||
StoredMultiAccount storeAccount(const QString& accountId, const StatusGo::HashedPassword& password);
|
||||
|
||||
AccountDto saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
MultiAccount saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& config);
|
||||
|
||||
QJsonObject getAccountDataForAccountId(const QString& accountId, const QString& displayName) const;
|
||||
|
||||
QJsonArray prepareSubaccountJsonObject(const GeneratedAccountDto& account, const QString& displayName) const;
|
||||
QJsonArray prepareSubaccountJsonObject(const GeneratedMultiAccount& account, const QString& displayName) const;
|
||||
|
||||
QJsonArray getSubaccountDataForAccountId(const QString& accountId, const QString& displayName) const;
|
||||
|
||||
QString generateSigningPhrase(int count) const;
|
||||
|
||||
QJsonObject prepareAccountSettingsJsonObject(const GeneratedAccountDto& account,
|
||||
QJsonObject prepareAccountSettingsJsonObject(const GeneratedMultiAccount& account,
|
||||
const QString& installationId,
|
||||
const QString& displayName) const;
|
||||
|
||||
|
@ -80,14 +82,14 @@ private:
|
|||
QJsonObject getDefaultNodeConfig(const QString& installationId) const;
|
||||
|
||||
private:
|
||||
std::vector<GeneratedAccountDto> m_generatedAccounts;
|
||||
std::vector<GeneratedMultiAccount> m_generatedAccounts;
|
||||
|
||||
fs::path m_statusgoDataDir;
|
||||
fs::path m_keyStoreDir;
|
||||
bool m_isFirstTimeAccountLogin;
|
||||
// TODO: don't see the need for this state here
|
||||
AccountDto m_loggedInAccount;
|
||||
GeneratedAccountDto m_importedAccount;
|
||||
MultiAccount m_loggedInAccount;
|
||||
GeneratedMultiAccount m_importedAccount;
|
||||
|
||||
// Here for now. Extract them if used by other services
|
||||
static constexpr auto m_keyStoreDirName = "keystore";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "AccountDto.h"
|
||||
#include "GeneratedAccountDto.h"
|
||||
#include "MultiAccount.h"
|
||||
#include "GeneratedMultiAccount.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
|
@ -20,18 +20,18 @@ public:
|
|||
virtual bool init(const fs::path& statusgoDataDir) = 0;
|
||||
|
||||
/// opens database and returns accounts list.
|
||||
[[nodiscard]] virtual std::vector<AccountDto> openAndListAccounts() = 0;
|
||||
[[nodiscard]] virtual std::vector<MultiAccount> openAndListAccounts() = 0;
|
||||
|
||||
/// Retrieve cached accounts generated in \c init
|
||||
[[nodiscard]] virtual const std::vector<GeneratedAccountDto>& generatedAccounts() const = 0;
|
||||
[[nodiscard]] virtual const std::vector<GeneratedMultiAccount>& generatedAccounts() const = 0;
|
||||
|
||||
/// Configure an generated account. \a accountID must be sourced from \c generatedAccounts
|
||||
virtual bool setupAccountAndLogin(const QString& accountID, const QString& password, const QString& displayName) = 0;
|
||||
|
||||
/// Account that is currently logged-in
|
||||
[[nodiscard]] virtual const AccountDto& getLoggedInAccount() const = 0;
|
||||
[[nodiscard]] virtual const MultiAccount& getLoggedInAccount() const = 0;
|
||||
|
||||
[[nodiscard]] virtual const GeneratedAccountDto& getImportedAccount() const = 0;
|
||||
[[nodiscard]] virtual const GeneratedMultiAccount& getImportedAccount() const = 0;
|
||||
|
||||
/// Check if the login was never done in the current \c data directory
|
||||
[[nodiscard]] virtual bool isFirstTimeAccountLogin() const = 0;
|
||||
|
@ -39,13 +39,13 @@ public:
|
|||
/// Set and initializes the keystore directory. \see StatusGo::General::initKeystore
|
||||
virtual bool setKeyStoreDir(const QString &key) = 0;
|
||||
|
||||
virtual QString login(AccountDto account, const QString& password) = 0;
|
||||
virtual QString login(MultiAccount account, const QString& password) = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual QString generateAlias(const QString& publicKey) = 0;
|
||||
|
||||
virtual void deleteMultiAccount(const AccountDto &account) = 0;
|
||||
virtual void deleteMultiAccount(const MultiAccount &account) = 0;
|
||||
};
|
||||
|
||||
using AccountsServiceInterfacePtr = std::shared_ptr<AccountsServiceInterface>;
|
||||
|
|
|
@ -50,19 +50,19 @@ struct DerivedAccounts
|
|||
for(const auto &derivationPath : jsonObj.keys())
|
||||
{
|
||||
auto derivedObj = jsonObj.value(derivationPath).toObject();
|
||||
if(derivationPath == Constants::General::PathWhisper)
|
||||
if(derivationPath == Constants::General::PathWhisper.get())
|
||||
{
|
||||
result.whisper = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathWalletRoot)
|
||||
else if(derivationPath == Constants::General::PathWalletRoot.get())
|
||||
{
|
||||
result.walletRoot = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathDefaultWallet)
|
||||
else if(derivationPath == Constants::General::PathDefaultWallet.get())
|
||||
{
|
||||
result.defaultWallet = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
else if(derivationPath == Constants::General::PathEIP1581)
|
||||
else if(derivationPath == Constants::General::PathEIP1581.get())
|
||||
{
|
||||
result.eip1581 = DerivedAccountDetails::toDerivedAccountDetails(derivedObj, derivationPath);
|
||||
}
|
||||
|
@ -72,28 +72,28 @@ struct DerivedAccounts
|
|||
}
|
||||
};
|
||||
|
||||
struct StoredAccountDto
|
||||
struct StoredMultiAccount
|
||||
{
|
||||
QString publicKey;
|
||||
QString address;
|
||||
|
||||
};
|
||||
|
||||
static StoredAccountDto toStoredAccountDto(const QJsonObject& jsonObj)
|
||||
static StoredMultiAccount toStoredMultiAccount(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = StoredAccountDto();
|
||||
auto result = StoredMultiAccount();
|
||||
|
||||
try {
|
||||
result.address = Json::getMandatoryProp(jsonObj, "address")->toString();
|
||||
result.publicKey = Json::getMandatoryProp(jsonObj, "publicKey")->toString();
|
||||
} catch (std::exception e) {
|
||||
qWarning() << QString("Mapping StoredAccountDto failed: %1").arg(e.what());
|
||||
qWarning() << QString("Mapping StoredMultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct GeneratedAccountDto
|
||||
struct GeneratedMultiAccount
|
||||
{
|
||||
QString id;
|
||||
QString publicKey;
|
||||
|
@ -110,9 +110,9 @@ struct GeneratedAccountDto
|
|||
return !(id.isEmpty() || publicKey.isEmpty() || address.isEmpty() || keyUid.isEmpty());
|
||||
}
|
||||
|
||||
static GeneratedAccountDto toGeneratedAccountDto(const QJsonObject& jsonObj)
|
||||
static GeneratedMultiAccount toGeneratedMultiAccount(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = GeneratedAccountDto();
|
||||
auto result = GeneratedMultiAccount();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -130,7 +130,7 @@ struct GeneratedAccountDto
|
|||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QString("Mapping GeneratedAccountDto failed: %1").arg(e.what());
|
||||
qWarning() << QString("Mapping GeneratedMultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
|
@ -4,14 +4,18 @@
|
|||
#include "Common/SigningPhrases.h"
|
||||
#include "Common/Json.h"
|
||||
|
||||
#include <StatusGo/Accounts/accounts_types.h>
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
// TODO: Move to StatusGo library
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
// TODO: refactor it to MultiAccount
|
||||
struct AccountDto
|
||||
/// \note equivalent of status-go's multiaccounts.Account@multiaccounts/database.go
|
||||
struct MultiAccount
|
||||
{
|
||||
QString name;
|
||||
long timestamp;
|
||||
|
@ -20,16 +24,16 @@ struct AccountDto
|
|||
// TODO images
|
||||
// TODO colorHash
|
||||
// TODO colorId
|
||||
QString address;
|
||||
Accounts::EOAddress address;
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return !(name.isEmpty() || keyUid.isEmpty());
|
||||
}
|
||||
|
||||
static AccountDto toAccountDto(const QJsonObject& jsonObj)
|
||||
static MultiAccount toMultiAccount(const QJsonObject& jsonObj)
|
||||
{
|
||||
auto result = AccountDto();
|
||||
auto result = MultiAccount();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -43,13 +47,13 @@ struct AccountDto
|
|||
}
|
||||
result.keycardPairing = Json::getMandatoryProp(jsonObj, "keycard-pairing")->toString();
|
||||
result.keyUid = Json::getMandatoryProp(jsonObj, "key-uid")->toString();
|
||||
result.address = Json::getProp(jsonObj, "address")->toString();
|
||||
result.address = Accounts::EOAddress(Json::getProp(jsonObj, "address")->toString());
|
||||
|
||||
/// TODO: investigate unhandled `photo-path` value
|
||||
}
|
||||
catch (std::exception e)
|
||||
{
|
||||
qWarning() << QObject::tr("Mapping AccountDto failed: %1").arg(e.what());
|
||||
qWarning() << QString("Mapping MultiAccount failed: %1").arg(e.what());
|
||||
}
|
||||
|
||||
return result;
|
|
@ -6,8 +6,8 @@ target_sources(${PROJECT_NAME}
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/UserAccount.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/UserAccountsModel.h
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/AccountDto.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/GeneratedAccountDto.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/MultiAccount.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/GeneratedMultiAccount.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/AccountsService.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Accounts/AccountsServiceInterface.h
|
||||
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <StatusGo/Accounts/accounts_types.h>
|
||||
|
||||
#include <QtCore>
|
||||
#include <QStringLiteral>
|
||||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
namespace Status::Constants
|
||||
{
|
||||
|
||||
|
@ -34,15 +38,15 @@ namespace General
|
|||
|
||||
inline const auto ZeroAddress = u"0x0000000000000000000000000000000000000000"_qs;
|
||||
|
||||
inline const auto PathWalletRoot = u"m/44'/60'/0'/0"_qs;
|
||||
inline const Accounts::DerivationPath PathWalletRoot{u"m/44'/60'/0'/0"_qs};
|
||||
// EIP1581 Root Key, the extended key from which any whisper key/encryption key can be derived
|
||||
inline const auto PathEIP1581 = u"m/43'/60'/1581'"_qs;
|
||||
inline const Accounts::DerivationPath PathEIP1581{u"m/43'/60'/1581'"_qs};
|
||||
// BIP44-0 Wallet key, the default wallet key
|
||||
inline const auto PathDefaultWallet = PathWalletRoot + u"/0"_qs;
|
||||
inline const Accounts::DerivationPath PathDefaultWallet{PathWalletRoot.get() + u"/0"_qs};
|
||||
// EIP1581 Chat Key 0, the default whisper key
|
||||
inline const auto PathWhisper = PathEIP1581 + u"/0'/0"_qs;
|
||||
inline const Accounts::DerivationPath PathWhisper{PathEIP1581.get() + u"/0'/0"_qs};
|
||||
|
||||
inline const QVector<QString> AccountDefaultPaths {PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet};
|
||||
inline const std::vector<Accounts::DerivationPath> AccountDefaultPaths {PathWalletRoot, PathEIP1581, PathWhisper, PathDefaultWallet};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "UserAccountsModel.h"
|
||||
|
||||
#include "Accounts/AccountsServiceInterface.h"
|
||||
#include "Accounts/AccountDto.h"
|
||||
#include "Accounts/MultiAccount.h"
|
||||
|
||||
#include <QtQmlIntegration>
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ OnboardingController::OnboardingController(AccountsServiceInterfacePtr accountsS
|
|||
{ // Init accounts
|
||||
std::vector<std::shared_ptr<UserAccount>> accounts;
|
||||
for(auto &account : getOpenedAccounts()) {
|
||||
accounts.push_back(std::make_shared<UserAccount>(std::make_unique<AccountDto>(std::move(account))));
|
||||
accounts.push_back(std::make_shared<UserAccount>(std::make_unique<MultiAccount>(std::move(account))));
|
||||
}
|
||||
m_accounts = std::make_shared<UserAccountsModel>(std::move(accounts));
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ void OnboardingController::onLogin(const QString& error)
|
|||
emit accountLoginError(error);
|
||||
}
|
||||
|
||||
std::vector<AccountDto> OnboardingController::getOpenedAccounts() const
|
||||
std::vector<MultiAccount> OnboardingController::getOpenedAccounts() const
|
||||
{
|
||||
return m_accountsService->openAndListAccounts();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "UserAccountsModel.h"
|
||||
|
||||
#include "Accounts/AccountDto.h"
|
||||
#include "Accounts/MultiAccount.h"
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QtQmlIntegration>
|
||||
|
@ -38,7 +38,7 @@ public:
|
|||
~OnboardingController();
|
||||
|
||||
/// Retrieve available accounts
|
||||
std::vector<AccountDto> getOpenedAccounts() const;
|
||||
std::vector<MultiAccount> getOpenedAccounts() const;
|
||||
|
||||
/// Login user account
|
||||
/// TODO: \a user should be of type \c UserAccount but this doesn't work with Qt6 CMake API. Investigate and fix later on
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#include "UserAccount.h"
|
||||
|
||||
#include "Accounts/AccountDto.h"
|
||||
|
||||
#include "Accounts/MultiAccount.h"
|
||||
|
||||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
UserAccount::UserAccount(std::unique_ptr<AccountDto> data)
|
||||
UserAccount::UserAccount(std::unique_ptr<MultiAccount> data)
|
||||
: QObject()
|
||||
, m_data(std::move(data))
|
||||
{
|
||||
|
@ -18,12 +17,12 @@ const QString &UserAccount::name() const
|
|||
return m_data->name;
|
||||
}
|
||||
|
||||
const AccountDto &UserAccount::accountData() const
|
||||
const MultiAccount &UserAccount::accountData() const
|
||||
{
|
||||
return *m_data;
|
||||
}
|
||||
|
||||
void UserAccount::updateAccountData(const AccountDto& newData)
|
||||
void UserAccount::updateAccountData(const MultiAccount& newData)
|
||||
{
|
||||
std::vector<std::function<void()>> notifyUpdates;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace Status::Onboarding
|
||||
{
|
||||
|
||||
class AccountDto;
|
||||
class MultiAccount;
|
||||
|
||||
/*!
|
||||
* \brief Represents a user account in Onboarding Presentation Layer
|
||||
|
@ -21,18 +21,18 @@ class UserAccount: public QObject
|
|||
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
public:
|
||||
explicit UserAccount(std::unique_ptr<AccountDto> data);
|
||||
explicit UserAccount(std::unique_ptr<MultiAccount> data);
|
||||
|
||||
const QString &name() const;
|
||||
|
||||
const AccountDto& accountData() const;
|
||||
void updateAccountData(const AccountDto& newData);
|
||||
const MultiAccount& accountData() const;
|
||||
void updateAccountData(const MultiAccount& newData);
|
||||
|
||||
signals:
|
||||
void nameChanged();
|
||||
|
||||
private:
|
||||
std::unique_ptr<AccountDto> m_data;
|
||||
std::unique_ptr<MultiAccount> m_data;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,12 +41,8 @@ target_link_libraries(${PROJECT_NAME}
|
|||
|
||||
Status::OnboardingTestHelpers
|
||||
Status::Onboarding
|
||||
|
||||
# TODO tmp
|
||||
Status::StatusGoQt
|
||||
)
|
||||
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_add_tests(
|
||||
TARGET ${PROJECT_NAME}
|
||||
|
|
|
@ -110,7 +110,7 @@ void ScopedTestAccount::logOut()
|
|||
throw std::runtime_error("ScopedTestAccount - failed logging out");
|
||||
}
|
||||
|
||||
Accounts::MultiAccount ScopedTestAccount::firstChatAccount()
|
||||
Accounts::ChatOrWalletAccount ScopedTestAccount::firstChatAccount()
|
||||
{
|
||||
auto accounts = Accounts::getAccounts();
|
||||
auto chatIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) {
|
||||
|
@ -121,7 +121,7 @@ Accounts::MultiAccount ScopedTestAccount::firstChatAccount()
|
|||
return *chatIt;
|
||||
}
|
||||
|
||||
Accounts::MultiAccount ScopedTestAccount::firstWalletAccount()
|
||||
Accounts::ChatOrWalletAccount ScopedTestAccount::firstWalletAccount()
|
||||
{
|
||||
auto accounts = Accounts::getAccounts();
|
||||
auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) {
|
||||
|
|
|
@ -36,8 +36,8 @@ public:
|
|||
void processMessages(size_t millis, std::function<bool()> shouldWaitUntilTimeout);
|
||||
void logOut();
|
||||
|
||||
static Accounts::MultiAccount firstChatAccount();
|
||||
static Accounts::MultiAccount firstWalletAccount();
|
||||
static Accounts::ChatOrWalletAccount firstChatAccount();
|
||||
static Accounts::ChatOrWalletAccount firstWalletAccount();
|
||||
|
||||
QString password() const { return m_accountPassword; };
|
||||
|
||||
|
|
|
@ -21,17 +21,17 @@ public:
|
|||
virtual ~AccountsServiceMock() override {};
|
||||
|
||||
MOCK_METHOD(bool, init, (const fs::path&), (override));
|
||||
MOCK_METHOD(std::vector<Onboarding::AccountDto>, openAndListAccounts, (), (override));
|
||||
MOCK_METHOD(const std::vector<Onboarding::GeneratedAccountDto>&, generatedAccounts, (), (const, override));
|
||||
MOCK_METHOD(std::vector<Onboarding::MultiAccount>, openAndListAccounts, (), (override));
|
||||
MOCK_METHOD(const std::vector<Onboarding::GeneratedMultiAccount>&, generatedAccounts, (), (const, override));
|
||||
MOCK_METHOD(bool, setupAccountAndLogin, (const QString&, const QString&, const QString&), (override));
|
||||
MOCK_METHOD(const Onboarding::AccountDto&, getLoggedInAccount, (), (const, override));
|
||||
MOCK_METHOD(const Onboarding::GeneratedAccountDto&, getImportedAccount, (), (const, override));
|
||||
MOCK_METHOD(const Onboarding::MultiAccount&, getLoggedInAccount, (), (const, override));
|
||||
MOCK_METHOD(const Onboarding::GeneratedMultiAccount&, getImportedAccount, (), (const, override));
|
||||
MOCK_METHOD(bool, isFirstTimeAccountLogin, (), (const, override));
|
||||
MOCK_METHOD(bool, setKeyStoreDir, (const QString&), (override));
|
||||
MOCK_METHOD(QString, login, (Onboarding::AccountDto, const QString&), (override));
|
||||
MOCK_METHOD(QString, login, (Onboarding::MultiAccount, const QString&), (override));
|
||||
MOCK_METHOD(void, clear, (), (override));
|
||||
MOCK_METHOD(QString, generateAlias, (const QString&), (override));
|
||||
MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::AccountDto&), (override));
|
||||
MOCK_METHOD(void, deleteMultiAccount, (const Onboarding::MultiAccount&), (override));
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ add_library(${PROJECT_NAME} SHARED)
|
|||
# Use by linker only
|
||||
set_property(GLOBAL PROPERTY DEBUG_CONFIGURATIONS Debug)
|
||||
|
||||
# TODO: consider adding a private header for parsing and keep json dependency away!?
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
Status::Helpers
|
||||
|
@ -76,10 +75,11 @@ target_sources(${PROJECT_NAME}
|
|||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/Accounts.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/Accounts.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/accounts_types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/AccountsAPI.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/AccountsAPI.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/MultiAccount.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/MultiAccount.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/ChatOrWalletAccount.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Accounts/ChatOrWalletAccount.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Messenger/Service.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/StatusGo/Messenger/Service.cpp
|
||||
|
|
|
@ -9,7 +9,7 @@ const int MNEMONIC_PHRASE_LENGTH = 12;
|
|||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
RpcResponse<QJsonArray> generateAddresses(const QVector<QString>& paths)
|
||||
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"n", NUMBER_OF_ADDRESSES_TO_GENERATE},
|
||||
|
@ -64,13 +64,12 @@ RpcResponse<QString> generateAlias(const QString& publicKey)
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const QString& hashedPassword,
|
||||
const QVector<QString>& paths)
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const HashedPassword& password, const std::vector<Accounts::DerivationPath>& paths)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"accountID", id},
|
||||
{"paths", Utils::toJsonArray(paths)},
|
||||
{"password", hashedPassword}
|
||||
{"password", password.get()}
|
||||
};
|
||||
|
||||
try
|
||||
|
@ -101,11 +100,11 @@ RpcResponse<QJsonObject> storeDerivedAccounts(const QString& id, const QString&
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const QString& hashedPassword)
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password)
|
||||
{
|
||||
QJsonObject payload{
|
||||
{"accountID", id},
|
||||
{"password", hashedPassword}
|
||||
{"password", password.get()}
|
||||
};
|
||||
|
||||
try
|
||||
|
@ -136,14 +135,14 @@ RpcResponse<QJsonObject> storeAccount(const QString& id, const QString& hashedPa
|
|||
}
|
||||
}
|
||||
|
||||
bool saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
bool saveAccountAndLogin(const HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto result = SaveAccountAndLogin(Utils::jsonToByteArray(account).data(),
|
||||
hashedPassword.toUtf8().data(),
|
||||
password.get().toUtf8().data(),
|
||||
Utils::jsonToByteArray(settings).data(),
|
||||
Utils::jsonToByteArray(nodeConfig).data(),
|
||||
Utils::jsonToByteArray(subaccounts).data());
|
||||
|
@ -193,7 +192,7 @@ RpcResponse<QJsonArray> openAccounts(const char* dataDirPath)
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large)
|
||||
{
|
||||
QJsonObject payload{
|
||||
|
@ -210,7 +209,7 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
|
|||
try
|
||||
{
|
||||
auto payloadData = Utils::jsonToByteArray(std::move(payload));
|
||||
auto result = Login(payloadData.data(), hashedPassword.toUtf8().data());
|
||||
auto result = Login(payloadData.data(), password.get().toUtf8().data());
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
|
@ -234,7 +233,7 @@ RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const
|
|||
}
|
||||
}
|
||||
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig)
|
||||
{
|
||||
QJsonObject payload{
|
||||
|
@ -252,7 +251,7 @@ RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& key
|
|||
{
|
||||
auto payloadData = Utils::jsonToByteArray(std::move(payload));
|
||||
auto nodeConfigData = Utils::jsonToByteArray(nodeConfig);
|
||||
auto result = LoginWithConfig(payloadData.data(), hashedPassword.toUtf8().data(), nodeConfigData.data());
|
||||
auto result = LoginWithConfig(payloadData.data(), password.get().toUtf8().data(), nodeConfigData.data());
|
||||
QJsonObject jsonResult;
|
||||
if(!Utils::checkReceivedResponse(result, jsonResult))
|
||||
{
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "accounts_types.h"
|
||||
|
||||
#include <QtCore>
|
||||
|
||||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
RpcResponse<QJsonArray> generateAddresses(const QVector<QString>& paths);
|
||||
RpcResponse<QJsonArray> generateAddresses(const std::vector<Accounts::DerivationPath> &paths);
|
||||
|
||||
RpcResponse<QString> generateAlias(const QString& publicKey);
|
||||
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId, const QString& hashedPassword,
|
||||
const QVector<QString>& paths);
|
||||
RpcResponse<QJsonObject> storeDerivedAccounts(const QString& accountId, const HashedPassword& password,
|
||||
const std::vector<Accounts::DerivationPath>& paths);
|
||||
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const QString& hashedPassword);
|
||||
RpcResponse<QJsonObject> storeAccount(const QString& id, const HashedPassword& password);
|
||||
|
||||
bool saveAccountAndLogin(const QString& hashedPassword, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig);
|
||||
bool saveAccountAndLogin(const StatusGo::HashedPassword& password, const QJsonObject& account,
|
||||
const QJsonArray& subaccounts, const QJsonObject& settings,
|
||||
const QJsonObject& nodeConfig);
|
||||
|
||||
/// opens database and returns accounts list.
|
||||
RpcResponse<QJsonArray> openAccounts(const char* dataDirPath);
|
||||
|
||||
/// TODO harmonise password parameters (hashed or plain)?
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
RpcResponse<QJsonObject> login(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large);
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const QString& hashedPassword,
|
||||
RpcResponse<QJsonObject> loginWithConfig(const QString& name, const QString& keyUid, const HashedPassword& password,
|
||||
const QString& thumbnail, const QString& large, const QJsonObject& nodeConfig);
|
||||
RpcResponse<QJsonObject> logout();
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ using json = nlohmann::json;
|
|||
namespace Status::StatusGo::Accounts
|
||||
{
|
||||
|
||||
Accounts::MultiAccounts getAccounts() {
|
||||
Accounts::ChatOrWalletAccounts getAccounts() {
|
||||
// or even nicer with a raw string literal
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
|
@ -29,10 +29,10 @@ Accounts::MultiAccounts getAccounts() {
|
|||
return resultJson.get<CallPrivateRpcResponse>().result;
|
||||
}
|
||||
|
||||
void generateAccountWithDerivedPath(const QString &hashedPassword, const QString &name, const QColor &color, const QString &emoji,
|
||||
const QString &path, const QString &derivedFrom)
|
||||
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name, const QColor &color, const QString &emoji,
|
||||
const DerivationPath &path, const EOAddress &derivedFrom)
|
||||
{
|
||||
std::vector<json> params = {hashedPassword, name, color, emoji, path, derivedFrom};
|
||||
std::vector<json> params = {password, name, color, emoji, path, derivedFrom};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_generateAccountWithDerivedPath"},
|
||||
|
@ -44,10 +44,10 @@ void generateAccountWithDerivedPath(const QString &hashedPassword, const QString
|
|||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const QString &hashedPassword, const QString &name,
|
||||
const QColor &color, const QString &emoji, const QString &path)
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji, const DerivationPath &path)
|
||||
{
|
||||
std::vector<json> params = {mnemonic, hashedPassword, name, color, emoji, path};
|
||||
std::vector<json> params = {mnemonic, password, name, color, emoji, path};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "accounts_addAccountWithMnemonicAndPath"},
|
||||
|
@ -59,7 +59,7 @@ void addAccountWithMnemonicAndPath(const QString &mnemonic, const QString &hashe
|
|||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void addAccountWatch(const QString &address, const QString &name, const QColor &color, const QString &emoji)
|
||||
void addAccountWatch(const EOAddress &address, const QString &name, const QColor &color, const QString &emoji)
|
||||
{
|
||||
std::vector<json> params = {address, name, color, emoji};
|
||||
json inputJson = {
|
||||
|
@ -73,7 +73,7 @@ void addAccountWatch(const QString &address, const QString &name, const QColor &
|
|||
checkPrivateRpcCallResultAndReportError(resultJson);
|
||||
}
|
||||
|
||||
void deleteAccount(const QString &address)
|
||||
void deleteAccount(const EOAddress &address)
|
||||
{
|
||||
std::vector<json> params = {address};
|
||||
json inputJson = {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#include "Accounts/MultiAccount.h"
|
||||
#include "Accounts/ChatOrWalletAccount.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
@ -16,34 +18,34 @@ namespace Status::StatusGo::Accounts
|
|||
/// \brief Retrieve all available accounts Wallet and Chat
|
||||
/// \note status-go returns accounts in \c CallPrivateRpcResponse.result
|
||||
/// \throws \c CallPrivateRpcError
|
||||
Accounts::MultiAccounts getAccounts();
|
||||
Accounts::ChatOrWalletAccounts getAccounts();
|
||||
|
||||
/// \brief Generate a new account
|
||||
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void generateAccountWithDerivedPath(const QString &password, const QString &name,
|
||||
void generateAccountWithDerivedPath(const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji,
|
||||
const QString &path, const QString &derivedFrom);
|
||||
const DerivationPath &path, const Accounts::EOAddress &derivedFrom);
|
||||
|
||||
/// \brief Add a new account from an existing mnemonic
|
||||
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const QString &hashedPassword, const QString &name,
|
||||
const QColor &color, const QString &emoji, const QString &path);
|
||||
void addAccountWithMnemonicAndPath(const QString &mnemonic, const HashedPassword &password, const QString &name,
|
||||
const QColor &color, const QString &emoji, const DerivationPath &path);
|
||||
|
||||
/// \brief Add a watch only account
|
||||
/// \note the underlying status-go api, SaveAccounts@accounts.go, returns `nil` for \c CallPrivateRpcResponse.result
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void addAccountWatch(const QString &address, const QString &name, const QColor &color, const QString &emoji);
|
||||
void addAccountWatch(const EOAddress &address, const QString &name, const QColor &color, const QString &emoji);
|
||||
|
||||
/// \brief Delete an existing account
|
||||
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
|
||||
/// \see \c getAccounts
|
||||
/// \throws \c CallPrivateRpcError
|
||||
void deleteAccount(const QString &address);
|
||||
void deleteAccount(const EOAddress &address);
|
||||
|
||||
/// \brief Delete an existing account
|
||||
/// \note the underlying status-go api, DeleteAccount@accounts.go, returns `os.Remove(keyFile)`
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "MultiAccount.h"
|
||||
#include "ChatOrWalletAccount.h"
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
void to_json(json& j, const MultiAccount& d) {
|
||||
void to_json(json& j, const ChatOrWalletAccount& d) {
|
||||
j = {{"address", d.address},
|
||||
{"chat", d.isChat},
|
||||
{"clock", d.clock},
|
||||
|
@ -21,7 +21,7 @@ void to_json(json& j, const MultiAccount& d) {
|
|||
j["derived-from"] = d.derivedFrom.value();
|
||||
}
|
||||
|
||||
void from_json(const json& j, MultiAccount& d) {
|
||||
void from_json(const json& j, ChatOrWalletAccount& d) {
|
||||
j.at("address").get_to(d.address);
|
||||
j.at("chat").get_to(d.isChat);
|
||||
j.at("clock").get_to(d.clock);
|
||||
|
@ -40,7 +40,7 @@ void from_json(const json& j, MultiAccount& d) {
|
|||
if(j.contains(publicKeyKey))
|
||||
j.at(publicKeyKey).get_to(d.publicKey);
|
||||
if(d.isWallet && !j.at("derived-from").get<std::string>().empty())
|
||||
d.derivedFrom = j.at("derived-from").get<QString>();
|
||||
d.derivedFrom = j.at("derived-from").get<std::optional<EOAddress>>();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include "accounts_types.h"
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
#include <QColor>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
|
||||
/// \brief Unique wallet account entity
|
||||
/// \note equivalent of status-go's accounts.Account@multiaccounts/accounts/database.go
|
||||
struct ChatOrWalletAccount
|
||||
{
|
||||
EOAddress address;
|
||||
bool isChat = false;
|
||||
int clock = -1;
|
||||
QColor color;
|
||||
std::optional<EOAddress> derivedFrom;
|
||||
QString emoji;
|
||||
bool isHidden = false;
|
||||
QString mixedcaseAddress;
|
||||
QString name;
|
||||
DerivationPath path;
|
||||
QString publicKey;
|
||||
bool isRemoved = false;
|
||||
bool isWallet = false;
|
||||
};
|
||||
|
||||
using ChatOrWalletAccounts = std::vector<ChatOrWalletAccount>;
|
||||
|
||||
void to_json(json& j, const ChatOrWalletAccount& d);
|
||||
void from_json(const json& j, ChatOrWalletAccount& d);
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
#include <QColor>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
// TODO: rename to MixedAccount
|
||||
// TODO: create custom types or just named types for all. Also fix APIs after this
|
||||
|
||||
/*! \brief Unique wallet account entity
|
||||
*/
|
||||
struct MultiAccount
|
||||
{
|
||||
QString address;
|
||||
bool isChat = false;
|
||||
int clock = -1;
|
||||
QColor color;
|
||||
std::optional<QString> derivedFrom;
|
||||
QString emoji;
|
||||
bool isHidden = false;
|
||||
QString mixedcaseAddress;
|
||||
QString name;
|
||||
QString path;
|
||||
QString publicKey;
|
||||
bool isRemoved = false;
|
||||
bool isWallet = false;
|
||||
};
|
||||
|
||||
using MultiAccounts = std::vector<MultiAccount>;
|
||||
|
||||
void to_json(json& j, const MultiAccount& d);
|
||||
void from_json(const json& j, MultiAccount& d);
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#include <Helpers/NamedType.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <QString>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
/// Defines phantom types for strong typing
|
||||
namespace Status::StatusGo::Accounts {
|
||||
|
||||
/// The 20 byte address of an Ethereum account prefixed with 0x
|
||||
using EOAddress = Helpers::NamedType<QString, struct EOAddressTag>;
|
||||
using DerivationPath = Helpers::NamedType<QString, struct DerivationPathTag>;
|
||||
|
||||
}
|
|
@ -1,10 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <Helpers/NamedType.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace Status::StatusGo
|
||||
{
|
||||
|
||||
using HashedPassword = Helpers::NamedType<QString, struct HashedPasswordTag>;
|
||||
|
||||
// Used in calls where we don't have version and id returned from `status-go`
|
||||
|
||||
struct RpcError
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
namespace Status::StatusGo::Utils
|
||||
{
|
||||
|
||||
QJsonArray toJsonArray(const QVector<QString>& value)
|
||||
QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value)
|
||||
{
|
||||
QJsonArray array;
|
||||
for(auto& v : value)
|
||||
array << v;
|
||||
array << v.get();
|
||||
return array;
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,10 @@ const char* statusGoCallPrivateRPC(const char* inputJSON) {
|
|||
return CallPrivateRPC(const_cast<char*>(inputJSON));
|
||||
}
|
||||
|
||||
QString hashString(const QString &str)
|
||||
HashedPassword hashPassword(const QString &str)
|
||||
{
|
||||
return "0x" + QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(),
|
||||
QCryptographicHash::Keccak_256).toHex());
|
||||
return HashedPassword("0x" + QString::fromUtf8(QCryptographicHash::hash(str.toUtf8(),
|
||||
QCryptographicHash::Keccak_256).toHex()));
|
||||
}
|
||||
|
||||
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
@ -26,7 +27,7 @@ QByteArray jsonToByteArray(const T& json)
|
|||
return QJsonDocument(json).toJson(QJsonDocument::Compact);
|
||||
}
|
||||
|
||||
QJsonArray toJsonArray(const QVector<QString>& value);
|
||||
QJsonArray toJsonArray(const std::vector<Accounts::DerivationPath>& value);
|
||||
|
||||
/// Check if json contains a standard status-go error and
|
||||
std::optional<RpcError> getRPCErrorInJson(const QJsonObject& json);
|
||||
|
@ -111,6 +112,6 @@ RpcResponse<T> callPrivateRpc(const QByteArray& payload)
|
|||
}
|
||||
}
|
||||
|
||||
QString hashString(const QString &str);
|
||||
HashedPassword hashPassword(const QString &str);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
#include <Helpers/conversions.h>
|
||||
|
||||
#include <QColor>
|
||||
|
@ -8,6 +10,8 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Wallet {
|
||||
|
@ -19,12 +23,10 @@ namespace Status::StatusGo::Wallet {
|
|||
*/
|
||||
struct DerivedAddress
|
||||
{
|
||||
// TODO create and Address type represents the 20 byte address of an Ethereum account. See https://pkg.go.dev/github.com/ethereum/go-ethereum/common?utm_source=gopls#Address
|
||||
QString address;
|
||||
// TODO: create an Path named type
|
||||
QString path;
|
||||
bool hasActivity = false;
|
||||
bool alreadyCreated = false;
|
||||
Accounts::EOAddress address;
|
||||
Accounts::DerivationPath path;
|
||||
bool hasActivity = false;
|
||||
bool alreadyCreated = false;
|
||||
};
|
||||
|
||||
using DerivedAddresses = std::vector<DerivedAddress>;
|
||||
|
|
|
@ -3,20 +3,24 @@
|
|||
#include "Utils.h"
|
||||
#include "Metadata/api_response.h"
|
||||
|
||||
#include "Accounts/accounts_types.h"
|
||||
|
||||
#include <libstatus.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace Accounts = Status::StatusGo::Accounts;
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace Status::StatusGo::Wallet
|
||||
{
|
||||
|
||||
DerivedAddresses getDerivedAddressesForPath(const QString &hashedPassword, const QString &derivedFrom, const QString &path, int pageSize, int pageNumber)
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, const Accounts::EOAddress &derivedFrom, const Accounts::DerivationPath &path, int pageSize, int pageNumber)
|
||||
{
|
||||
std::vector<json> params = {hashedPassword, derivedFrom, path, pageSize, pageNumber};
|
||||
std::vector<json> params = {password, derivedFrom, path, pageSize, pageNumber};
|
||||
json inputJson = {
|
||||
{"jsonrpc", "2.0"},
|
||||
{"method", "wallet_getDerivedAddressesForPath"},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "Accounts/MultiAccount.h"
|
||||
#include "Accounts/ChatOrWalletAccount.h"
|
||||
#include "Accounts/accounts_types.h"
|
||||
#include "DerivedAddress.h"
|
||||
#include "Types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -13,6 +14,6 @@ namespace Status::StatusGo::Wallet
|
|||
/// \brief Retrieve a list of derived account addresses
|
||||
/// \see \c generateAccountWithDerivedPath
|
||||
/// \throws \c CallPrivateRpcError
|
||||
DerivedAddresses getDerivedAddressesForPath(const QString &password, const QString &derivedFrom, const QString &path, int pageSize, int pageNumber);
|
||||
DerivedAddresses getDerivedAddressesForPath(const HashedPassword &password, const Accounts::EOAddress &derivedFrom, const Accounts::DerivationPath &path, int pageSize, int pageNumber);
|
||||
|
||||
} // namespaces
|
||||
|
|
|
@ -13,7 +13,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
|
||||
# Required to suppress "qmllint may not work" warning
|
||||
|
|
|
@ -10,7 +10,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Containers
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
LayoutSpacer.qml
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Controls
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
StatusBanner.qml
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Controls.Navigation
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
ApplicationContentView.qml
|
||||
ApplicationSection.qml
|
||||
|
|
|
@ -10,7 +10,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Core
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
StatusBaseText.qml
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ qt6_add_qml_module(${PROJECT_NAME}
|
|||
URI Status.Core.Theme
|
||||
VERSION 1.0
|
||||
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
QML_FILES
|
||||
StatusColors.qml
|
||||
StatusDarkPalette.qml
|
||||
|
|
|
@ -12,8 +12,9 @@ qt6_standard_project_setup()
|
|||
qt6_add_qml_module(${PROJECT_NAME}
|
||||
URI Status.TestHelpers
|
||||
VERSION 1.0
|
||||
# TODO: temporary until we make qt_target_qml_sources work
|
||||
|
||||
QML_FILES
|
||||
|
||||
# Required to suppress "qmllint may not work" warning
|
||||
OUTPUT_DIRECTORY
|
||||
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Status/TestHelpers
|
||||
|
|
|
@ -36,14 +36,14 @@ TEST(AccountsAPI, TestGetAccounts)
|
|||
ASSERT_NE(chatIt, accounts.end());
|
||||
const auto &chatAccount = *chatIt;
|
||||
ASSERT_EQ(chatAccount.name, testAccountName);
|
||||
ASSERT_FALSE(chatAccount.path.isEmpty());
|
||||
ASSERT_FALSE(chatAccount.path.get().isEmpty());
|
||||
ASSERT_FALSE(chatAccount.derivedFrom.has_value());
|
||||
|
||||
const auto walletIt = std::find_if(accounts.begin(), accounts.end(), [](const auto& a) { return a.isWallet; });
|
||||
ASSERT_NE(walletIt, accounts.end());
|
||||
const auto &walletAccount = *walletIt;
|
||||
ASSERT_NE(walletAccount.name, testAccountName);
|
||||
ASSERT_FALSE(walletAccount.path.isEmpty());
|
||||
ASSERT_FALSE(walletAccount.path.get().isEmpty());
|
||||
ASSERT_TRUE(walletAccount.derivedFrom.has_value());
|
||||
}
|
||||
|
||||
|
@ -53,14 +53,14 @@ TEST(Accounts, TestGenerateAccountWithDerivedPath)
|
|||
constexpr auto testAccountPassword = "password*";
|
||||
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName, testAccountPassword, true);
|
||||
|
||||
auto hashedPassword{Utils::hashString(testAccountPassword)};
|
||||
auto password{Utils::hashPassword(testAccountPassword)};
|
||||
const auto newTestAccountName = u"test_generated_new_account-name"_qs;
|
||||
const auto newTestAccountColor = QColor("fuchsia");
|
||||
const auto newTestAccountEmoji = u""_qs;
|
||||
const auto newTestAccountPath = Status::Constants::General::PathWalletRoot;
|
||||
|
||||
const auto chatAccount = testAccount.firstChatAccount();
|
||||
Accounts::generateAccountWithDerivedPath(hashedPassword, newTestAccountName,
|
||||
Accounts::generateAccountWithDerivedPath(password, newTestAccountName,
|
||||
newTestAccountColor, newTestAccountEmoji,
|
||||
newTestAccountPath, chatAccount.address);
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
|
@ -72,13 +72,13 @@ TEST(Accounts, TestGenerateAccountWithDerivedPath)
|
|||
});
|
||||
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
||||
const auto &newAccount = *newAccountIt;
|
||||
ASSERT_FALSE(newAccount.address.isEmpty());
|
||||
ASSERT_FALSE(newAccount.address.get().isEmpty());
|
||||
ASSERT_FALSE(newAccount.isChat);
|
||||
ASSERT_FALSE(newAccount.isWallet);
|
||||
ASSERT_EQ(newAccount.color, newTestAccountColor);
|
||||
ASSERT_FALSE(newAccount.derivedFrom.has_value());
|
||||
ASSERT_EQ(newAccount.emoji, newTestAccountEmoji);
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.toUpper());
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.get().toUpper());
|
||||
ASSERT_EQ(newAccount.path, newTestAccountPath);
|
||||
ASSERT_FALSE(newAccount.publicKey.isEmpty());
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ TEST(AccountsAPI, TestGenerateAccountWithDerivedPath_WrongPassword)
|
|||
|
||||
const auto chatAccount = testAccount.firstChatAccount();
|
||||
try {
|
||||
Accounts::generateAccountWithDerivedPath(Utils::hashString("WrongPassword"), u"test_wrong_pass-name"_qs,
|
||||
Accounts::generateAccountWithDerivedPath(Utils::hashPassword("WrongPassword"), u"test_wrong_pass-name"_qs,
|
||||
QColor("fuchsia"), "", Status::Constants::General::PathWalletRoot,
|
||||
chatAccount.address);
|
||||
FAIL();
|
||||
|
@ -111,14 +111,14 @@ TEST(AccountsAPI, TestAddAccountWithMnemonicAndPath)
|
|||
constexpr auto testAccountPassword = "password*";
|
||||
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName, testAccountPassword, true);
|
||||
|
||||
auto hashedPassword{Utils::hashString(testAccountPassword)};
|
||||
auto password{Utils::hashPassword(testAccountPassword)};
|
||||
const auto newTestAccountName = u"test_import_from_mnemonic-name"_qs;
|
||||
const auto newTestAccountColor = QColor("fuchsia");
|
||||
const auto newTestAccountEmoji = u""_qs;
|
||||
const auto newTestAccountPath = Status::Constants::General::PathWalletRoot;
|
||||
|
||||
Accounts::addAccountWithMnemonicAndPath("festival october control quarter husband dish throw couch depth stadium cigar whisper",
|
||||
hashedPassword, newTestAccountName, newTestAccountColor, newTestAccountEmoji,
|
||||
password, newTestAccountName, newTestAccountColor, newTestAccountEmoji,
|
||||
newTestAccountPath);
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
ASSERT_EQ(updatedAccounts.size(), 3);
|
||||
|
@ -129,13 +129,13 @@ TEST(AccountsAPI, TestAddAccountWithMnemonicAndPath)
|
|||
});
|
||||
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
||||
const auto &newAccount = *newAccountIt;
|
||||
ASSERT_FALSE(newAccount.address.isEmpty());
|
||||
ASSERT_FALSE(newAccount.address.get().isEmpty());
|
||||
ASSERT_FALSE(newAccount.isChat);
|
||||
ASSERT_FALSE(newAccount.isWallet);
|
||||
ASSERT_EQ(newAccount.color, newTestAccountColor);
|
||||
ASSERT_FALSE(newAccount.derivedFrom.has_value());
|
||||
ASSERT_EQ(newAccount.emoji, newTestAccountEmoji);
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.toUpper());
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.get().toUpper());
|
||||
ASSERT_EQ(newAccount.path, newTestAccountPath);
|
||||
ASSERT_FALSE(newAccount.publicKey.isEmpty());
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ TEST(AccountsAPI, TestAddAccountWithMnemonicAndPath_WrongMnemonicWorks)
|
|||
constexpr auto testAccountPassword = "password*";
|
||||
ScopedTestAccount testAccount(test_info_->name(), testRootAccountName, testAccountPassword, true);
|
||||
|
||||
auto hashedPassword{Utils::hashString(testAccountPassword)};
|
||||
auto password{Utils::hashPassword(testAccountPassword)};
|
||||
const auto newTestAccountName = u"test_import_from_wrong_mnemonic-name"_qs;
|
||||
const auto newTestAccountColor = QColor("fuchsia");
|
||||
const auto newTestAccountEmoji = u""_qs;
|
||||
|
@ -155,7 +155,7 @@ TEST(AccountsAPI, TestAddAccountWithMnemonicAndPath_WrongMnemonicWorks)
|
|||
|
||||
// Added an inexistent word. The mnemonic is not checked.
|
||||
Accounts::addAccountWithMnemonicAndPath("october control quarter husband dish throw couch depth stadium cigar waku",
|
||||
hashedPassword, newTestAccountName, newTestAccountColor, newTestAccountEmoji,
|
||||
password, newTestAccountName, newTestAccountColor, newTestAccountEmoji,
|
||||
newTestAccountPath);
|
||||
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
|
@ -168,13 +168,13 @@ TEST(AccountsAPI, TestAddAccountWithMnemonicAndPath_WrongMnemonicWorks)
|
|||
|
||||
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
||||
const auto &newAccount = *newAccountIt;
|
||||
ASSERT_FALSE(newAccount.address.isEmpty());
|
||||
ASSERT_FALSE(newAccount.address.get().isEmpty());
|
||||
ASSERT_FALSE(newAccount.isChat);
|
||||
ASSERT_FALSE(newAccount.isWallet);
|
||||
ASSERT_EQ(newAccount.color, newTestAccountColor);
|
||||
ASSERT_FALSE(newAccount.derivedFrom.has_value());
|
||||
ASSERT_EQ(newAccount.emoji, newTestAccountEmoji);
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.toUpper());
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.get().toUpper());
|
||||
ASSERT_EQ(newAccount.path, newTestAccountPath);
|
||||
ASSERT_FALSE(newAccount.publicKey.isEmpty());
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ TEST(AccountsAPI, TestAddAccountWatch)
|
|||
const auto newTestAccountColor = QColor("fuchsia");
|
||||
const auto newTestAccountEmoji = u""_qs;
|
||||
|
||||
Accounts::addAccountWatch("0x145b6B821523afFC346774b41ACC7b77A171BbA4", newTestAccountName, newTestAccountColor, newTestAccountEmoji);
|
||||
Accounts::addAccountWatch(Accounts::EOAddress("0x145b6B821523afFC346774b41ACC7b77A171BbA4"), newTestAccountName, newTestAccountColor, newTestAccountEmoji);
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
ASSERT_EQ(updatedAccounts.size(), 3);
|
||||
|
||||
|
@ -199,14 +199,14 @@ TEST(AccountsAPI, TestAddAccountWatch)
|
|||
});
|
||||
ASSERT_NE(newAccountIt, updatedAccounts.end());
|
||||
const auto &newAccount = *newAccountIt;
|
||||
ASSERT_FALSE(newAccount.address.isEmpty());
|
||||
ASSERT_FALSE(newAccount.address.get().isEmpty());
|
||||
ASSERT_FALSE(newAccount.isChat);
|
||||
ASSERT_FALSE(newAccount.isWallet);
|
||||
ASSERT_EQ(newAccount.color, newTestAccountColor);
|
||||
ASSERT_FALSE(newAccount.derivedFrom.has_value());
|
||||
ASSERT_EQ(newAccount.emoji, newTestAccountEmoji);
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.toUpper());
|
||||
ASSERT_TRUE(newAccount.path.isEmpty());
|
||||
ASSERT_EQ(newAccount.mixedcaseAddress.toUpper(), newAccount.address.get().toUpper());
|
||||
ASSERT_TRUE(newAccount.path.get().isEmpty());
|
||||
ASSERT_TRUE(newAccount.publicKey.isEmpty());
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ TEST(AccountsAPI, TestDeleteAccount)
|
|||
const auto newTestAccountColor = QColor("fuchsia");
|
||||
const auto newTestAccountEmoji = u""_qs;
|
||||
|
||||
Accounts::addAccountWatch("0x145b6B821523afFC346774b41ACC7b77A171BbA4", newTestAccountName, newTestAccountColor, newTestAccountEmoji);
|
||||
Accounts::addAccountWatch(Accounts::EOAddress("0x145b6B821523afFC346774b41ACC7b77A171BbA4"), newTestAccountName, newTestAccountColor, newTestAccountEmoji);
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
ASSERT_EQ(updatedAccounts.size(), 3);
|
||||
|
||||
|
|
|
@ -32,11 +32,11 @@ TEST(WalletApi, TestGetDerivedAddressesForPath)
|
|||
const auto rootAccount = testAccount.onboardingController()->accountsService()->getLoggedInAccount();
|
||||
ASSERT_EQ(rootAccount.address, walletAccount.derivedFrom.value());
|
||||
|
||||
const auto hashedPassword{Utils::hashString(testAccountPassword)};
|
||||
const auto password{Utils::hashPassword(testAccountPassword)};
|
||||
const auto testPath = Status::Constants::General::PathWalletRoot;
|
||||
|
||||
// chatAccount.address
|
||||
const auto chatDerivedAddresses = Wallet::getDerivedAddressesForPath(hashedPassword, chatAccount.address, testPath, 3, 1);
|
||||
const auto chatDerivedAddresses = Wallet::getDerivedAddressesForPath(password, chatAccount.address, testPath, 3, 1);
|
||||
// Check that no change is done
|
||||
const auto updatedAccounts = Accounts::getAccounts();
|
||||
ASSERT_EQ(updatedAccounts.size(), 2);
|
||||
|
@ -47,14 +47,14 @@ TEST(WalletApi, TestGetDerivedAddressesForPath)
|
|||
// all hasActivity are false
|
||||
ASSERT_TRUE(std::none_of(chatDerivedAddresses.begin(), chatDerivedAddresses.end(), [](const auto& a) { return a.hasActivity; }));
|
||||
// all address are valid
|
||||
ASSERT_TRUE(std::none_of(chatDerivedAddresses.begin(), chatDerivedAddresses.end(), [](const auto& a) { return a.address.isEmpty(); }));
|
||||
ASSERT_TRUE(std::none_of(chatDerivedAddresses.begin(), chatDerivedAddresses.end(), [](const auto& a) { return a.address.get().isEmpty(); }));
|
||||
|
||||
const auto walletDerivedAddresses = Wallet::getDerivedAddressesForPath(hashedPassword, walletAccount.address, testPath, 2, 1);
|
||||
const auto walletDerivedAddresses = Wallet::getDerivedAddressesForPath(password, walletAccount.address, testPath, 2, 1);
|
||||
ASSERT_EQ(walletDerivedAddresses.size(), 2);
|
||||
// all alreadyCreated are false
|
||||
ASSERT_TRUE(std::none_of(walletDerivedAddresses.begin(), walletDerivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; }));
|
||||
|
||||
const auto rootDerivedAddresses = Wallet::getDerivedAddressesForPath(hashedPassword, rootAccount.address, testPath, 4, 1);
|
||||
const auto rootDerivedAddresses = Wallet::getDerivedAddressesForPath(password, rootAccount.address, testPath, 4, 1);
|
||||
ASSERT_EQ(rootDerivedAddresses.size(), 4);
|
||||
ASSERT_EQ(std::count_if(rootDerivedAddresses.begin(), rootDerivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; }), 1);
|
||||
const auto &existingAddress = *std::find_if(rootDerivedAddresses.begin(), rootDerivedAddresses.end(), [](const auto& a) { return a.alreadyCreated; });
|
||||
|
|
Loading…
Reference in New Issue