Where Settings and Preferences Are Managed in the Amnezia-Client Codebase

The amnezia-client application manages all user preferences through a centralized three-layer architecture centered on the SecureAppSettingsRepository class, which persists data via SecureQSettings while SettingsController and SettingsUiController handle business logic and UI bindings.

The amnezia-vpn/amnezia-client repository implements a robust, layered approach to settings management that separates persistence, business logic, and presentation concerns. Understanding where settings are stored and how they flow through the system is essential for contributors and security researchers auditing the VPN client. All user-configurable options—from DNS servers to kill-switch states—flow through specific controller and repository classes defined in the client source tree.

The Three-Layer Settings Architecture

SecureAppSettingsRepository: The Core Persistence Layer

The SecureAppSettingsRepository class serves as the single source of truth for all persistent user preferences. Located in client/core/repositories/secureAppSettingsRepository.h (and its corresponding .cpp implementation), this repository wraps a SecureQSettings instance—a thin abstraction over Qt’s native QSettings that adds encryption for sensitive values.

This layer exposes typed getter and setter methods for every configurable option. For example, DNS preferences are managed through useAmneziaDns() and setUseAmneziaDns(bool) (lines 30-32), while kill-switch status uses isKillSwitchEnabled() and setKillSwitchEnabled(bool) (lines 65-66). Language settings are handled via getAppLanguage() and setAppLanguage(QLocale) (lines 27-28), and auto-connect functionality uses isAutoConnect() and setAutoConnect(bool) (lines 70-71).

SettingsController: The Business Logic Facade

Sitting between the repository and the UI, the SettingsController class in client/core/controllers/settingsController.h translates high-level actions into repository calls. It exposes Qt slots like toggleAmneziaDns(bool) and toggleLogging(bool) (implemented in settingsController.cpp, lines 43-51 and 73-81) that validate and forward changes to SecureAppSettingsRepository.

The controller also emits signals such as killSwitchEnabledChanged (defined in settingsController.cpp, lines 53-55) to notify the UI of state changes, enabling reactive updates without direct coupling to the persistence layer.

SettingsUiController: The UI Binding Layer

The presentation layer resides in client/ui/controllers/settingsUiController.h, where SettingsUiController connects Qt widgets to the SettingsController. This class forwards user interactions—for example, when a user toggles a switch in the preferences dialog—and reflects state changes back to the interface through Qt’s signal/slot mechanism.

Complete Data Flow from UI to Storage

When a user modifies a setting, data flows through four distinct layers:

  1. UI Widget captures the interaction in SettingsUiController
  2. SettingsUiController invokes the appropriate slot on SettingsController
  3. SettingsController validates the request and calls SecureAppSettingsRepository
  4. SecureAppSettingsRepository persists the value via SecureQSettings (defined in client/core/utils/secureQSettings.h)

Platform-specific build configurations for settings like autostart are handled in cmake/platform_settings.cmake, though these intersect with the repository layer at runtime.

Key Settings Methods and File References

The following table maps specific preferences to their managing classes and source locations:

  • DNS Usage: Managed by SecureAppSettingsRepository via useAmneziaDns() / setUseAmneziaDns(bool) in secureAppSettingsRepository.h (lines 30-32)
  • Primary/Secondary DNS: Same repository using primaryDns() / setPrimaryDns(const QString&) (lines 34-36)
  • Kill-Switch: isKillSwitchEnabled() / setKillSwitchEnabled(bool) (lines 65-66)
  • Auto-Connect: isAutoConnect() / setAutoConnect(bool) (lines 70-71)
  • Application Language: getAppLanguage() / setAppLanguage(QLocale) (lines 27-28)
  • UI Toggles: SettingsController forwards calls through toggleAmneziaDns(bool) and toggleLogging(bool) (settingsController.cpp, lines 43-51, 73-81)

Code Examples

The following examples demonstrate how to interact with the settings system programmatically:

// Enable Amnezia DNS from anywhere in the code
SettingsController settingsCtrl(serversRepo, appSettingsRepo);
settingsCtrl.toggleAmneziaDns(true);   // stores the flag via SecureAppSettingsRepository
// Read the current UI language
QLocale currentLang = settingsCtrl.getAppLanguage();   // forwards to repository
// React to a change in the kill-switch state (Qt signal/slot)
connect(&settingsCtrl, &SettingsController::killSwitchEnabledChanged,
        [](){ qDebug() << "Kill-switch state changed!"; });

Summary

  • SecureAppSettingsRepository in client/core/repositories/ is the ultimate authority for persisting all user preferences through SecureQSettings.
  • SettingsController in client/core/controllers/ provides a business-logic façade with signal/slot interfaces for the rest of the application.
  • SettingsUiController in client/ui/controllers/ binds Qt widgets to the controller layer, ensuring UI state remains synchronized with persistence.
  • Sensitive data is encrypted via the SecureQSettings wrapper before reaching Qt’s native QSettings storage.

Frequently Asked Questions

What class actually writes settings to disk in amnezia-client?

The SecureAppSettingsRepository class handles all disk persistence. It wraps SecureQSettings (found in client/core/utils/secureQSettings.h), which encrypts sensitive values before storing them via Qt’s QSettings mechanism.

How does the UI layer communicate with the settings backend?

The UI uses SettingsUiController to capture widget interactions, which forwards calls to SettingsController. The controller then invokes methods on SecureAppSettingsRepository, ensuring the UI remains decoupled from direct storage operations.

Where are kill-switch and DNS preferences defined in the source code?

These reside in client/core/repositories/secureAppSettingsRepository.h. Kill-switch state uses isKillSwitchEnabled() and setKillSwitchEnabled(bool) (lines 65-66), while DNS settings use useAmneziaDns() / setUseAmneziaDns(bool) (lines 30-32) and primaryDns() / setPrimaryDns(const QString&) (lines 34-36).

Is SettingsController just a pass-through to SecureAppSettingsRepository?

No. While SettingsController forwards many calls to the repository, it adds validation logic and emits Qt signals (like killSwitchEnabledChanged) that enable reactive UI updates. It also handles higher-level operations such as toggleLogging(bool), providing a clean API for the presentation layer.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →