1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
"""
This module manages the Proton VPN general settings.
Copyright (c) 2023 Proton AG
This file is part of Proton VPN.
Proton VPN is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Proton VPN is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ProtonVPN. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
from dataclasses import dataclass
import os
from proton.vpn import logging
from proton.utils.environment import VPNExecutionEnvironment
from proton.vpn.core.cache_handler import CacheHandler
from proton.vpn.killswitch.interface import KillSwitchState
from proton.vpn.core.settings.custom_dns import CustomDNS
from proton.vpn.core.settings.features import Features
logger = logging.getLogger(__name__)
SETTINGS = os.path.join(
VPNExecutionEnvironment().path_config,
"settings.json"
)
DEFAULT_PROTOCOL = "wireguard"
DEFAULT_KILLSWITCH = KillSwitchState.OFF.value
DEFAULT_ANONYMOUS_CRASH_REPORTS = True
@dataclass
class Settings:
"""Contains general settings."""
protocol: str
killswitch: int
custom_dns: CustomDNS
ipv6: bool
anonymous_crash_reports: bool
features: Features
@staticmethod
def from_dict(data: dict, user_tier: int) -> Settings:
"""Creates and returns `Settings` from the provided dict."""
default = Settings.default(user_tier)
features = data.get("features")
features = Features.from_dict(
features, user_tier) if features else default.features
custom_dns = data.get("custom_dns")
custom_dns = CustomDNS.from_dict(
custom_dns) if custom_dns else default.custom_dns
return Settings(
protocol=data.get("protocol", default.protocol),
killswitch=data.get("killswitch", default.killswitch),
custom_dns=custom_dns,
ipv6=data.get("ipv6", default.ipv6),
anonymous_crash_reports=data.get(
"anonymous_crash_reports",
default.anonymous_crash_reports
),
features=features
)
def to_dict(self) -> dict:
"""Converts the class to dict."""
return {
"protocol": self.protocol,
"killswitch": self.killswitch,
"custom_dns": self.custom_dns.to_dict(),
"ipv6": self.ipv6,
"anonymous_crash_reports": self.anonymous_crash_reports,
"features": self.features.to_dict(),
}
@staticmethod
def default(user_tier: int) -> Settings:
"""Creates and returns `Settings` from default configurations."""
return Settings(
protocol=DEFAULT_PROTOCOL,
killswitch=DEFAULT_KILLSWITCH,
custom_dns=CustomDNS.default(),
ipv6=True,
anonymous_crash_reports=DEFAULT_ANONYMOUS_CRASH_REPORTS,
features=Features.default(user_tier),
)
class SettingsPersistence:
"""Persists user settings"""
def __init__(self, cache_handler: CacheHandler = None):
self._cache_handler = cache_handler or CacheHandler(SETTINGS)
self._settings = None
self._settings_are_default = True
def get(self, user_tier: int) -> Settings:
"""Load the user settings, either the ones stored on disk or getting
default based on tier"""
if self._settings is not None:
return self._settings
raw_settings = self._cache_handler.load()
if raw_settings is None:
self._settings = Settings.default(user_tier)
else:
self._settings = Settings.from_dict(raw_settings, user_tier)
self._settings_are_default = False
return self._settings
def save(self, settings: Settings):
"""Store settings to disk."""
self._cache_handler.save(settings.to_dict())
self._settings = settings
self._settings_are_default = False
def delete(self):
"""Deletes the file stored on disk containing the settings
and resets internal settings property."""
self._cache_handler.remove()
self._settings = None
self._settings_are_default = True
|