mirror of
https://github.com/amnezia-vpn/amnezia-client.git
synced 2026-11-12 07:23:19 +09:00
* feat: move amnezia hardcode from sources to cmake * feat: move amnezia hardcode from sources to cmake * refactor: remove prem v1 migration * chore: move more branding * fix: use host-matching architecture for iOS simulator builds x86_64 was hardcoded; Apple Silicon Macs run arm64 simulators and Xcode 26 has no Rosetta simulator destinations, so simulators showed as unsupported. * fix: mark the branded media assets catalog as a bundle resource MACOSX_PACKAGE_LOCATION was set on the upstream Media.xcassets path while target_sources uses CLIENT_IOS_MEDIA_ASSETS_PATH, so a branded catalog was never compiled by actool and the app got a blank icon. * fix: parametrize the Swift app-group identifier used by Log.swift Log.swift hardcoded Amnezia's own app-group instead of the branded one, since Swift -D flags can't carry the string value like the ObjC++ side does. Generate a small Swift constants file instead, same pattern as version.h.in, wired into all four targets that compile Log.swift. * fix: use APPLICATION_NAME instead of hardcoded Amnezia in log line format Every log line printed "Amnezia" regardless of branding; the log file name two lines above this already used APPLICATION_NAME correctly. * fix: restore branding fixes dropped by rebase, rename swiftInterop to swiftBridge * fix: move more branding variables to cmake * feat: move macOS branding from sources to cmake - macos/app/Info.plist.in: app group, camera usage text, UTI ids and descriptions now come from CLIENT_APPLICATION_NAME / BUILD_* variables, mirroring ios/app/Info.plist.in - macos/networkextension/Info.plist.in: bundle names and app group ids are templated; the plist is configured by CMake into the binary dir because Xcode only expands its own $(...) settings - new knobs: CLIENT_MACOS_MEDIA_ASSETS_PATH, CLIENT_MACOS_APP_ICNS_PATH, CLIENT_MACOS_PROVISIONING_PROFILE_SPECIFIER(_DEBUG), CLIENT_MACOS_NE_PROVISIONING_PROFILE_SPECIFIER(_DEBUG) * fix: resolve macOS pf template paths relative to the client source dir CMAKE_SOURCE_DIR points at the wrapper project when the client is built as a subproject, so the pf template lookup failed there. * chore: separate brandings defaults --------- Co-authored-by: vkamn <vk@amnezia.org>
419 lines
14 KiB
C++
419 lines
14 KiB
C++
#include "serversController.h"
|
|
#include "core/utils/serverConfigUtils.h"
|
|
#include "core/utils/protocolEnum.h"
|
|
#include "core/protocols/protocolUtils.h"
|
|
#include "core/utils/constants/configKeys.h"
|
|
#include "core/models/containerConfig.h"
|
|
|
|
#include "core/models/serverDescription.h"
|
|
|
|
#if defined(Q_OS_IOS) || defined(MACOS_NE)
|
|
#include "core/utils/swiftBridge.h"
|
|
#endif
|
|
|
|
|
|
ServersController::ServersController(SecureServersRepository *serversRepository,
|
|
SecureAppSettingsRepository *appSettingsRepository, QObject *parent)
|
|
: QObject(parent), m_serversRepository(serversRepository), m_appSettingsRepository(appSettingsRepository)
|
|
{
|
|
ensureDefaultServerValid();
|
|
}
|
|
|
|
void ServersController::ensureDefaultServerValid()
|
|
{
|
|
if (!getServersCount()) {
|
|
return;
|
|
}
|
|
|
|
const QString defaultId = getDefaultServerId();
|
|
if (!defaultId.isEmpty() && indexOfServerId(defaultId) >= 0) {
|
|
return;
|
|
}
|
|
|
|
const QString firstId = getServerId(0);
|
|
if (!firstId.isEmpty()) {
|
|
setDefaultServer(firstId);
|
|
}
|
|
}
|
|
|
|
bool ServersController::renameServer(const QString &serverId, const QString &name)
|
|
{
|
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
|
switch (kind) {
|
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
|
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
|
if (!cfg.has_value()) return false;
|
|
cfg->description = name;
|
|
cfg->displayName = name;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return true;
|
|
}
|
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
|
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
|
if (!cfg.has_value()) return false;
|
|
cfg->description = name;
|
|
cfg->displayName = name;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return true;
|
|
}
|
|
case serverConfigUtils::ConfigType::Native: {
|
|
auto cfg = m_serversRepository->nativeConfig(serverId);
|
|
if (!cfg.has_value()) return false;
|
|
cfg->description = name;
|
|
cfg->displayName = name;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return true;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
|
auto cfg = m_serversRepository->apiV2Config(serverId);
|
|
if (!cfg.has_value()) return false;
|
|
cfg->name = name;
|
|
cfg->displayName = name;
|
|
cfg->nameOverriddenByUser = true;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return true;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
|
case serverConfigUtils::ConfigType::Invalid:
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ServersController::removeServer(const QString &serverId)
|
|
{
|
|
m_serversRepository->removeServer(serverId);
|
|
}
|
|
|
|
void ServersController::setDefaultServer(const QString &serverId)
|
|
{
|
|
m_serversRepository->setDefaultServer(serverId);
|
|
}
|
|
|
|
void ServersController::setDefaultContainer(const QString &serverId, DockerContainer container)
|
|
{
|
|
const serverConfigUtils::ConfigType kind = m_serversRepository->serverKind(serverId);
|
|
switch (kind) {
|
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
|
auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
|
if (!cfg.has_value()) return;
|
|
cfg->defaultContainer = container;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return;
|
|
}
|
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
|
auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
|
if (!cfg.has_value()) return;
|
|
cfg->defaultContainer = container;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return;
|
|
}
|
|
case serverConfigUtils::ConfigType::Native: {
|
|
auto cfg = m_serversRepository->nativeConfig(serverId);
|
|
if (!cfg.has_value()) return;
|
|
cfg->defaultContainer = container;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
|
auto cfg = m_serversRepository->apiV2Config(serverId);
|
|
if (!cfg.has_value()) return;
|
|
cfg->defaultContainer = container;
|
|
m_serversRepository->editServer(serverId, cfg->toJson(), kind);
|
|
return;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV2:
|
|
case serverConfigUtils::ConfigType::Invalid:
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
QVector<ServerDescription> ServersController::buildServerDescriptions(bool isAmneziaDnsEnabled) const
|
|
{
|
|
QVector<ServerDescription> out;
|
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
|
out.reserve(ids.size());
|
|
|
|
for (const QString &id : ids) {
|
|
ServerDescription d;
|
|
using Kind = serverConfigUtils::ConfigType;
|
|
const Kind kind = m_serversRepository->serverKind(id);
|
|
switch (kind) {
|
|
case Kind::SelfHostedAdmin: {
|
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(id);
|
|
if (!cfg) {
|
|
continue;
|
|
}
|
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
|
break;
|
|
}
|
|
case Kind::SelfHostedUser: {
|
|
const auto cfg = m_serversRepository->selfHostedUserConfig(id);
|
|
if (!cfg) {
|
|
continue;
|
|
}
|
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
|
break;
|
|
}
|
|
case Kind::Native: {
|
|
const auto cfg = m_serversRepository->nativeConfig(id);
|
|
if (!cfg) {
|
|
continue;
|
|
}
|
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
|
break;
|
|
}
|
|
case Kind::AmneziaPremiumV2:
|
|
case Kind::AmneziaFreeV3:
|
|
case Kind::ExternalPremium: {
|
|
const auto cfg = m_serversRepository->apiV2Config(id);
|
|
if (!cfg) {
|
|
continue;
|
|
}
|
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
|
break;
|
|
}
|
|
case Kind::AmneziaPremiumV1:
|
|
case Kind::AmneziaFreeV2: {
|
|
const auto cfg = m_serversRepository->legacyApiConfig(id);
|
|
if (!cfg) {
|
|
continue;
|
|
}
|
|
d = buildServerDescription(*cfg, isAmneziaDnsEnabled);
|
|
break;
|
|
}
|
|
case Kind::Invalid:
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
d.serverId = id;
|
|
out.append(d);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
QMap<DockerContainer, ContainerConfig> ServersController::getServerContainersMap(const QString &serverId) const
|
|
{
|
|
switch (m_serversRepository->serverKind(serverId)) {
|
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
|
}
|
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
|
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
|
}
|
|
case serverConfigUtils::ConfigType::Native: {
|
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
|
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
|
|
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
|
|
return cfg.has_value() ? cfg->containers : QMap<DockerContainer, ContainerConfig>{};
|
|
}
|
|
case serverConfigUtils::ConfigType::Invalid:
|
|
default:
|
|
return {};
|
|
}
|
|
}
|
|
|
|
DockerContainer ServersController::getDefaultContainer(const QString &serverId) const
|
|
{
|
|
switch (m_serversRepository->serverKind(serverId)) {
|
|
case serverConfigUtils::ConfigType::SelfHostedAdmin: {
|
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
|
}
|
|
case serverConfigUtils::ConfigType::SelfHostedUser: {
|
|
const auto cfg = m_serversRepository->selfHostedUserConfig(serverId);
|
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
|
}
|
|
case serverConfigUtils::ConfigType::Native: {
|
|
const auto cfg = m_serversRepository->nativeConfig(serverId);
|
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV2:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV3:
|
|
case serverConfigUtils::ConfigType::ExternalPremium: {
|
|
const auto cfg = m_serversRepository->apiV2Config(serverId);
|
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
|
}
|
|
case serverConfigUtils::ConfigType::AmneziaPremiumV1:
|
|
case serverConfigUtils::ConfigType::AmneziaFreeV2: {
|
|
const auto cfg = m_serversRepository->legacyApiConfig(serverId);
|
|
return cfg.has_value() ? cfg->defaultContainer : DockerContainer::None;
|
|
}
|
|
case serverConfigUtils::ConfigType::Invalid:
|
|
default:
|
|
return DockerContainer::None;
|
|
}
|
|
}
|
|
|
|
ContainerConfig ServersController::getContainerConfig(const QString &serverId, DockerContainer container) const
|
|
{
|
|
return getServerContainersMap(serverId).value(container);
|
|
}
|
|
|
|
int ServersController::getDefaultServerIndex() const
|
|
{
|
|
return m_serversRepository->defaultServerIndex();
|
|
}
|
|
|
|
QString ServersController::getDefaultServerId() const
|
|
{
|
|
return m_serversRepository->defaultServerId();
|
|
}
|
|
|
|
int ServersController::getServersCount() const
|
|
{
|
|
return m_serversRepository->serversCount();
|
|
}
|
|
|
|
QString ServersController::getServerId(int serverIndex) const
|
|
{
|
|
return m_serversRepository->serverIdAt(serverIndex);
|
|
}
|
|
|
|
int ServersController::indexOfServerId(const QString &serverId) const
|
|
{
|
|
return m_serversRepository->indexOfServerId(serverId);
|
|
}
|
|
|
|
QString ServersController::notificationDisplayName(const QString &serverId) const
|
|
{
|
|
if (serverId.isEmpty()) {
|
|
return {};
|
|
}
|
|
|
|
using Kind = serverConfigUtils::ConfigType;
|
|
switch (m_serversRepository->serverKind(serverId)) {
|
|
case Kind::SelfHostedAdmin: {
|
|
if (const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId)) {
|
|
if (!cfg->displayName.isEmpty()) {
|
|
return cfg->displayName;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Kind::SelfHostedUser: {
|
|
if (const auto cfg = m_serversRepository->selfHostedUserConfig(serverId)) {
|
|
if (!cfg->displayName.isEmpty()) {
|
|
return cfg->displayName;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Kind::Native: {
|
|
if (const auto cfg = m_serversRepository->nativeConfig(serverId)) {
|
|
if (!cfg->displayName.isEmpty()) {
|
|
return cfg->displayName;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Kind::AmneziaPremiumV2:
|
|
case Kind::AmneziaFreeV3:
|
|
case Kind::ExternalPremium: {
|
|
if (const auto cfg = m_serversRepository->apiV2Config(serverId)) {
|
|
if (!cfg->displayName.isEmpty()) {
|
|
return cfg->displayName;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Kind::AmneziaPremiumV1:
|
|
case Kind::AmneziaFreeV2: {
|
|
if (const auto cfg = m_serversRepository->legacyApiConfig(serverId)) {
|
|
if (!cfg->displayName.isEmpty()) {
|
|
return cfg->displayName;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
const int idx = indexOfServerId(serverId);
|
|
if (idx >= 0) {
|
|
return QString::number(idx + 1);
|
|
}
|
|
return serverId;
|
|
}
|
|
|
|
std::optional<ApiV2ServerConfig> ServersController::apiV2Config(const QString &serverId) const
|
|
{
|
|
return m_serversRepository->apiV2Config(serverId);
|
|
}
|
|
|
|
std::optional<SelfHostedAdminServerConfig> ServersController::selfHostedAdminConfig(const QString &serverId) const
|
|
{
|
|
return m_serversRepository->selfHostedAdminConfig(serverId);
|
|
}
|
|
|
|
ServerCredentials ServersController::getServerCredentials(const QString &serverId) const
|
|
{
|
|
const auto cfg = m_serversRepository->selfHostedAdminConfig(serverId);
|
|
if (cfg.has_value()) {
|
|
const ServerCredentials creds = cfg->credentials();
|
|
if (creds.isValid()) {
|
|
return creds;
|
|
}
|
|
}
|
|
return ServerCredentials {};
|
|
}
|
|
|
|
bool ServersController::isServerFromApiAlreadyExists(const QString &userCountryCode, const QString &serviceType,
|
|
const QString &serviceProtocol) const
|
|
{
|
|
const QVector<QString> ids = m_serversRepository->orderedServerIds();
|
|
for (const QString &id : ids) {
|
|
const auto apiV2 = m_serversRepository->apiV2Config(id);
|
|
if (!apiV2.has_value()) {
|
|
continue;
|
|
}
|
|
if (apiV2->apiConfig.userCountryCode == userCountryCode && apiV2->serviceType() == serviceType
|
|
&& apiV2->serviceProtocol() == serviceProtocol) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ServersController::hasInstalledContainers(const QString &serverId) const
|
|
{
|
|
const QMap<DockerContainer, ContainerConfig> containers = getServerContainersMap(serverId);
|
|
|
|
for (auto it = containers.begin(); it != containers.end(); ++it) {
|
|
DockerContainer container = it.key();
|
|
if (ContainerUtils::containerService(container) == ServiceType::Vpn) {
|
|
return true;
|
|
}
|
|
if (container == DockerContainer::SSXray) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ServersController::isLegacyApiV1Server(const QString &serverId) const
|
|
{
|
|
return !serverId.isEmpty()
|
|
&& serverConfigUtils::isLegacyApiSubscription(m_serversRepository->serverKind(serverId));
|
|
}
|