1. Overview
The SettingsStore.hpp header defines the SettingsStore class, a static configuration and persistence layer responsible for managing BastionGuard’s application settings and a dedicated secure payments domain list stored in payments.json. The component uses a JSON-backed cache, provides thread-safe access through a mutex, and supports initialization, reload, flush-to-disk, and reset-to-defaults workflows.
Functionally, SettingsStore provides:
- Centralized JSON-based settings storage with caching
- Thread-safe initialization, reload, and flush semantics
- Reset-to-defaults support for both settings and payment domain data
- Typed accessors for common primitives (bool/int/string) via dotted keys
- Secure payments feature toggle getters/setters
- Two-tier payments domain management (system defaults + user overrides)
- Atomic JSON writes to reduce corruption risk
2. Dependencies and Includes
#include <string>
#include <vector>
#include <mutex>
#include <nlohmann/json.hpp>
- <string> – key names, paths, and string settings values
- <vector> – list of payment domains and collection APIs
- <mutex> – thread-safety for the internal cache and I/O operations
- nlohmann/json.hpp – JSON representation, parsing, and serialization
3. Class Declaration and Scope
class SettingsStore
The class is structured as a static utility container. All methods and storage are declared static, and no instances of SettingsStore are intended to be created. This design provides a single process-wide source of truth for configuration and associated file I/O.
4. Public Interface
4.1 Lifecycle and Persistence
static void init();
static void reload();
static bool flush();
static bool reset_to_defaults();
- init() – initializes the settings store and loads settings into the cache
- reload() – forces a re-read from disk, replacing cached content
- flush() – writes the cached settings back to disk
- reset_to_defaults() – resets settings to default values and persists them
4.2 Secure Payments Feature Toggle
static bool get_secure_payments_enabled();
static void set_secure_payments_enabled(bool enabled);
Getter/setter for the secure payments feature flag. This flag typically controls whether BastionGuard enforces or enables a protected browsing/workflow for payments-related domains.
4.3 Payments Domains List Management (payments.json)
static void ensure_payments_json_exists();
// merge system + user, dedup, sorted
static std::vector<std::string> get_payment_domains();
// saves ONLY to user file (~/.config/BastionGuard/payments.json)
static bool save_payment_domains_user(const std::vector<std::string>& domains);
// reset user = system
static bool reset_payment_domains_from_system();
- ensure_payments_json_exists() – ensures a user-scoped
payments.jsonexists (seeded if needed) - get_payment_domains() – returns merged domains from system + user sources, de-duplicated and sorted
- save_payment_domains_user() – persists only the user list (does not overwrite system defaults)
- reset_payment_domains_from_system() – restores user list to match system defaults
5. UI Components
This component does not define UI widgets. It is a backend persistence and settings access layer intended to be used by pages such as SettingsPage, secure payments/banking UI, and other modules requiring configuration state.
6. Internal State and Data Model
static std::mutex mtx_;
static bool loaded_;
static nlohmann::json cache_;
- mtx_ – synchronizes access to the cache and disk I/O
- loaded_ – indicates whether the cache has been populated
- cache_ – in-memory JSON document holding the current settings state
The store is expected to follow a “load-once, reuse often” pattern: settings are loaded into cache_ and served to callers without repeated disk access, while flush() persists changes when needed.
7. User Actions (Callbacks)
No direct UI callbacks are declared. Calls are made programmatically by UI components and services when users change settings, modify lists, or restore defaults.
8. Internal Logic
8.1 Settings Document and Defaults
static std::string settings_file_path();
static nlohmann::json defaults();
- settings_file_path() – resolves the filesystem location of the main settings JSON
- defaults() – produces the default JSON document used when initializing or resetting
8.2 Loading and Writing (Locked)
static void ensure_loaded_locked();
static bool load_from_disk_locked();
static bool write_to_disk_locked(const nlohmann::json& j);
Internal load/write helpers are designed to be called under mtx_, guaranteeing that the cache remains consistent and preventing concurrent disk writes.
8.3 Dotted-Key Navigation
static nlohmann::json* get_or_create_node_locked(nlohmann::json& root, const std::string& dotted_key);
static const nlohmann::json* get_node_locked(const nlohmann::json& root, const std::string& dotted_key);
Provides access to nested settings nodes using dotted keys (e.g., "security.payments.enabled"). The “get-or-create” variant ensures intermediate nodes exist for setters.
8.4 Typed Accessors
static bool get_bool(const std::string& dotted_key, bool fallback_default);
static void set_bool(const std::string& dotted_key, bool value);
static int get_int(const std::string& dotted_key, int fallback_default);
static void set_int(const std::string& dotted_key, int value);
static std::string get_string(const std::string& dotted_key, const std::string& fallback_default);
static void set_string(const std::string& dotted_key, const std::string& value);
Implements typed read/write operations with fallback defaults to ensure robustness when keys are missing or configuration files are partially populated.
8.5 payments.json Helpers
static std::string user_payments_path();
static std::string system_payments_path();
static nlohmann::json default_payments_seed();
static bool read_json_file(const std::string& path, nlohmann::json& out);
static bool write_json_atomic(const std::string& path, const nlohmann::json& j);
- user_payments_path() – resolves user-scoped payments list location
- system_payments_path() – resolves system-scoped default payments list location
- default_payments_seed() – provides a seed JSON document when user file is missing
- read_json_file() – loads JSON from disk into an output object
- write_json_atomic() – writes JSON using an atomic pattern (temp + rename)
9. Auto-Update (Scheduled Refresh)
This component does not implement timers. Settings are loaded on demand and cached; consumers may call reload() when they need to synchronize with external changes, and flush() to persist updates.
10. Settings Storage
The store implements a two-tier persistence approach:
- Main settings JSON – stored at a path resolved by
settings_file_path() - Payments domains list – split into system defaults (
system_payments_path()) and user overrides (user_payments_path())
The merge policy for payment domains is explicitly documented in the API: system and user lists are merged, de-duplicated, and sorted before being returned.
11. Helper Functions and Filesystem Layout
Although exact paths are implementation-defined, the header documents user-scoped storage for payment domains as:
~/.config/BastionGuard/payments.json
System defaults are similarly expected to live under a read-only installation directory. A typical deployment may resemble:
/usr/share/BastionGuard/data/... (system resources)
~/.config/BastionGuard/settings.json (user settings)
~/.config/BastionGuard/payments.json (user payment domains)
12. Runtime and Security Considerations
- Thread safety: all cache access and disk I/O should be synchronized via
mtx_to prevent races and partial writes. - Atomic writes: JSON persistence should use an atomic write strategy (
write_json_atomic()) to avoid corruption on crash or power loss. - Input validation: payment domains saved via
save_payment_domains_user()should be normalized (lowercased, trimmed, canonical hostnames) to reduce duplication and bypass risk. - Trust boundary: system payments list is assumed trusted and read-only; user lists may be modified locally and should be validated before use in security decisions.
- Secrets handling: if the settings JSON stores sensitive values (API keys, tokens), ensure proper filesystem permissions and avoid logging sensitive content.
- Resilience: the
defaults()mechanism should keep the application functional even when settings files are missing or invalid.