You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
4.3 KiB
C++

// SPDX-FileCopyrightText: 2026 Reion Wong <reionwong@gmail.com>
// SPDX-License-Identifier: BSD-3-Clause
#include "cutefish/networkmanager/hotspot.h"
#include "cutefish/networkmanager/client.h"
#include "cutefish/networkmanager/variants.h"
#include "cutefish/networkmanager/wifi_utils.h"
#include <memory>
#include <unistd.h>
#include "base/event_loop.h"
namespace cutefish::networkmanager {
using namespace variants;
static std::string hostName()
{
char name[256] = {};
if (gethostname(name, sizeof(name) - 1) != 0)
return {};
return name;
}
HotspotConfiguration* HotspotConfiguration::instance()
{
static thread_local std::unique_ptr<HotspotConfiguration> configuration;
static thread_local bool hooked = false;
// Made again when the shared client was.
if (!configuration || configuration->m_client != Client::instance()) {
configuration = std::make_unique<HotspotConfiguration>();
base::EventLoop* loop = base::EventLoop::current();
if (loop && !hooked) {
hooked = true;
loop->addDestroyHook([] { configuration.reset(); });
}
}
return configuration.get();
}
HotspotConfiguration::HotspotConfiguration()
: m_client(Client::instance())
, m_generatedPassword(wifi::generatedPassword())
{
m_subscriptions.push_back(m_client->readyChanged.connect([this] { load(); }));
// A profile made or edited later, here or elsewhere, is read again.
m_subscriptions.push_back(m_client->changed.connect([this] {
if (connection() != m_loadedProfile || m_client->settings(connection()) != m_loadedSettings)
load();
}));
load();
}
HotspotConfiguration::~HotspotConfiguration() = default;
std::string HotspotConfiguration::connection() const
{
return m_client->hotspotConnection();
}
std::string HotspotConfiguration::name() const
{
if (!m_name.empty())
return m_name;
const std::string profile = connection();
if (!profile.empty())
return wifi::ssidLabel(toBytes(m_client->setting(profile, "802-11-wireless", "ssid")));
const std::string host = hostName();
return host.empty() || host == "localhost" ? std::string("Hotspot") : host;
}
std::string HotspotConfiguration::password() const
{
if (!m_password.empty())
return m_password;
return m_profilePassword.empty() ? m_generatedPassword : m_profilePassword;
}
void HotspotConfiguration::setName(const std::string& name)
{
if (name == this->name())
return;
m_name = name;
changed.emit();
}
void HotspotConfiguration::setPassword(const std::string& password)
{
if (password == this->password())
return;
m_password = password;
changed.emit();
}
bool HotspotConfiguration::nameValid(const std::string& name)
{
return !name.empty() && name.size() <= 32;
}
bool HotspotConfiguration::passwordValid(const std::string& password)
{
return wifi::pskValid(password);
}
std::string HotspotConfiguration::generatePassword()
{
return wifi::generatedPassword();
}
// The profile keeps its password with NetworkManager, which reads it out only on request.
void HotspotConfiguration::load()
{
const std::string profile = connection();
m_loadedProfile = profile;
m_loadedSettings = m_client->settings(profile);
if (profile.empty())
return;
changed.emit();
m_client->call(profile, connectionInterface, "GetSecrets", {base::dbus::Variant(std::string("802-11-wireless-security"))},
&m_context, [this](const base::dbus::Reply& reply) {
const auto secrets = reply.value<Settings>();
if (!secrets)
return;
const auto security = secrets->find("802-11-wireless-security");
if (security == secrets->end())
return;
std::string password = toString(value(security->second, "psk"));
if (!contains(security->second, "psk"))
password = toString(value(security->second, "wep-key0"));
if (password.empty() || password == m_profilePassword)
return;
m_profilePassword = password;
changed.emit();
});
}
} // namespace cutefish::networkmanager