1
Fork 0
mirror of https://github.com/redstrate/Astra.git synced 2025-05-13 21:07:46 +00:00
astra/launcher/src/account.cpp

165 lines
4 KiB
C++

// SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
// SPDX-License-Identifier: GPL-3.0-or-later
#include "account.h"
#include <cotp.h>
#include <qcorocore.h>
#include <qt6keychain/keychain.h>
#include "accountconfig.h"
#include "astra_log.h"
#include "utility.h"
using namespace Qt::StringLiterals;
Account::Account(const QString &key, QObject *parent)
: QObject(parent)
, m_config(new AccountConfig(key, this))
, m_key(key)
{
fetchPassword();
}
Account::~Account()
{
m_config->save();
}
QString Account::uuid() const
{
return m_key;
}
QString Account::avatarUrl() const
{
return m_avatarUrl;
}
QString Account::getPassword()
{
return QCoro::waitFor(getKeychainValue(QStringLiteral("password")));
}
void Account::setPassword(const QString &password)
{
setKeychainValue(QStringLiteral("password"), password);
if (m_needsPassword) {
m_needsPassword = false;
Q_EMIT needsPasswordChanged();
}
}
void Account::setAvatarUrl(const QString &url)
{
if (m_avatarUrl != url) {
m_avatarUrl = url;
Q_EMIT avatarUrlChanged();
}
}
QString Account::getOTP()
{
const auto otpSecret = QCoro::waitFor(getKeychainValue(QStringLiteral("otp-secret")));
if (otpSecret.isEmpty()) {
return {};
}
cotp_error err;
char *totp = get_totp(otpSecret.toStdString().c_str(), 6, 30, SHA1, &err);
if (err == NO_ERROR) {
QString totpStr = QString::fromLatin1(totp);
free(totp);
return totpStr;
} else {
return {};
}
}
void Account::setOTPSecret(const QString &secret)
{
setKeychainValue(QStringLiteral("otp-secret"), secret);
}
QDir Account::getConfigDir() const
{
const QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
const QDir userDir = dataDir.absoluteFilePath(QStringLiteral("user"));
return userDir.absoluteFilePath(m_key);
}
QString Account::getConfigPath() const
{
return getConfigDir().absolutePath();
}
void Account::setKeychainValue(const QString &key, const QString &value)
{
if (Utility::isSteamDeck()) {
auto stateConfig = KSharedConfig::openStateConfig();
stateConfig->group(QStringLiteral("Passwords")).writeEntry(m_key + QStringLiteral("-") + key, value);
stateConfig->sync();
} else {
auto job = new QKeychain::WritePasswordJob(QStringLiteral("Astra"), this);
job->setTextData(value);
#ifdef FLATPAK
job->setKey(QStringLiteral("flatpak-") + m_key + QStringLiteral("-") + key);
#else
job->setKey(m_key + QStringLiteral("-") + key);
#endif
job->start();
connect(job, &QKeychain::WritePasswordJob::finished, this, [job] {
if (job->error() != QKeychain::NoError) {
qWarning(ASTRA_LOG) << "Error when writing" << job->errorString();
}
});
}
}
QCoro::Task<QString> Account::getKeychainValue(const QString &key)
{
if (Utility::isSteamDeck()) {
co_return KSharedConfig::openStateConfig()->group(QStringLiteral("Passwords")).readEntry(m_key + QStringLiteral("-") + key);
} else {
auto job = new QKeychain::ReadPasswordJob(QStringLiteral("Astra"), this);
#ifdef FLATPAK
job->setKey(QStringLiteral("flatpak-") + m_key + QStringLiteral("-") + key);
#else
job->setKey(m_key + QStringLiteral("-") + key);
#endif
job->start();
co_await qCoro(job, &QKeychain::ReadPasswordJob::finished);
if (job->error() != QKeychain::NoError) {
qWarning(ASTRA_LOG) << "Error when reading" << key << job->errorString() << "for account" << uuid();
}
co_return job->textData();
}
}
bool Account::needsPassword() const
{
return m_needsPassword;
}
QCoro::Task<> Account::fetchPassword()
{
const QString password = co_await getKeychainValue(QStringLiteral("password"));
m_needsPassword = password.isEmpty();
Q_EMIT needsPasswordChanged();
co_return;
}
AccountConfig *Account::config() const
{
return m_config;
}
#include "moc_account.cpp"