1use std::fs;
2use std::net::SocketAddr;
3use std::path::Path;
4
5use std::sync::Arc;
6use parking_lot::Mutex;
7
8use product_os_configuration::VPNProvider;
9pub use product_os_configuration::VPN as VPNConfig;
10
11use product_os_utilities::ProductOSError;
12use crate::protocols::NetworkProtocol;
13pub use crate::protocols::Status;
14
15mod protocols;
16mod providers;
17
18
19#[derive(Clone)]
20pub struct ProductOSVPN {
21 provider: Arc<Mutex<dyn providers::Provider + Send + Sync>>,
22 credentials: Credentials,
23 configs_path: String,
24 configs_source: ConfigurationSource,
25 network_protocol: NetworkProtocol
26}
27
28#[derive(Clone)]
29pub struct Credentials {
30 credentials_path: String,
31 identifier: String,
32 key: String
33}
34
35#[derive(Clone)]
36pub struct ConfigurationSource {
37 archive: Option<String>,
38 page: Option<String>
39}
40
41
42impl ProductOSVPN {
43 pub fn new(config: product_os_configuration::VPN) -> Self {
44 let relative_path_res = std::env::current_dir();
45 let relative_path_root = match relative_path_res {
46 Ok(path) => path.into_os_string().into_string().unwrap(),
47 Err(_) => panic!("Problem getting current working directory")
48 };
49
50 let mut configs_path = match config.config_path.chars().nth(0).unwrap().to_string().as_str() {
51 "/" => config.config_path.to_owned(),
52 _ => {
53 let mut path = relative_path_root.clone();
54 path.push_str("/");
55 path.push_str(config.config_path.as_str());
56 path
57 }
58 };
59
60 if !configs_path.ends_with("/") {
61 configs_path.push_str("/");
62 }
63
64 let creds_path = match config.credentials_path.chars().nth(0).unwrap().to_string().as_str() {
65 "/" => config.credentials_path.to_owned(),
66 _ => {
67 let mut path = relative_path_root.clone();
68 path.push_str("/");
69 path.push_str(config.credentials_path.as_str());
70 path
71 }
72 };
73
74 let path_configs_path = Path::new(configs_path.as_str());
75 if !path_configs_path.exists() || !path_configs_path.is_dir() {
76 match fs::create_dir_all(path_configs_path) {
77 Ok(_) => {}
78 Err(e) => panic!("Config path {:?} does not exist and could not be created: {}", path_configs_path, e.to_string())
79 }
80 };
81
82 let credentials = Credentials {
83 credentials_path: creds_path,
84 identifier: config.identifier,
85 key: config.key
86 };
87
88 let configs_source = ConfigurationSource {
89 archive: config.config_server_archive,
90 page: config.config_server_page
91 };
92
93 let network_protocol = match config.network_protocol {
94 product_os_configuration::NetworkProtocol::UDP => NetworkProtocol::TCP,
95 product_os_configuration::NetworkProtocol::TCP => NetworkProtocol::UDP,
96 product_os_configuration::NetworkProtocol::ANY => {
97 match std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH) {
98 Ok(n) => {
99 match n.as_secs().rem_euclid(2) {
100 0 => NetworkProtocol::TCP,
101 _ => NetworkProtocol::UDP
102 }
103 },
104 Err(_) => panic!("SystemTime before UNIX EPOCH!"),
105 }
106 }
107 };
108
109 let provider = match config.provider {
110 VPNProvider::NordVPN => {
111 configs_path.push_str("nordvpn/");
112 Arc::new(Mutex::new(providers::nordvpn::NordVPN::new(configs_path.to_owned(), credentials.credentials_path.to_owned(),
113 config.bind_host, configs_source.to_owned(), network_protocol.clone())))
114 }
115 };
116
117 Self {
118 provider,
119 credentials,
120 configs_path,
121 configs_source,
122 network_protocol
123 }
124 }
125
126 pub fn connect(&mut self) -> Status {
127 let provider_unlocked = self.provider.clone();
128 let mut provider = provider_unlocked.lock();
129
130 provider.connect()
131 }
132
133 pub fn disconnect(&mut self) -> Status {
134 let provider_unlocked = self.provider.clone();
135 let mut provider = provider_unlocked.lock();
136
137 provider.disconnect()
138 }
139
140 pub fn get_status(&self) -> Status {
141 let provider_unlocked = self.provider.clone();
142 let provider = provider_unlocked.lock();
143
144 provider.get_status()
145 }
146
147 pub async fn update_configuration(&mut self, download: bool, extract: bool) -> Result<(), ProductOSError> {
148 let provider_unlocked = self.provider.clone();
149 let mut provider = provider_unlocked.lock();
150
151 provider.refresh_config(download, extract).await
152 }
153
154 pub fn get_host(&self) -> String {
155 let provider_unlocked = self.provider.clone();
156 let provider = provider_unlocked.lock();
157
158 provider.get_host()
159 }
160
161 pub fn get_port(&self) -> u16 {
162 let provider_unlocked = self.provider.clone();
163 let provider = provider_unlocked.lock();
164
165 provider.get_port()
166 }
167
168 pub fn get_address(&self) -> SocketAddr {
169 let provider_unlocked = self.provider.clone();
170 let provider = provider_unlocked.lock();
171
172 product_os_utilities::ProductOSUtilities::get_socket_address(provider.get_host().as_str(), provider.get_port(), true)
173 }
174}