1
1
use super :: Mullvad ;
2
- use super :: { AuthToken , UserInfo , UserResponse , WireguardProvider } ;
3
- use crate :: config:: providers:: { BoolChoice , ConfigurationChoice , Input , InputNumericu16 , UiClient } ;
2
+ use super :: WireguardProvider ;
3
+ use crate :: config:: providers:: { ConfigurationChoice , Input , InputNumericu16 , UiClient } ;
4
4
use crate :: network:: wireguard:: { WireguardConfig , WireguardInterface , WireguardPeer } ;
5
5
use crate :: util:: delete_all_files_in_dir;
6
- use crate :: util:: wireguard:: { generate_keypair , generate_public_key, WgKey , WgPeer } ;
7
- use anyhow:: { anyhow , Context } ;
6
+ use crate :: util:: wireguard:: { generate_public_key, WgKey , WgPeer } ;
7
+ use anyhow:: Context ;
8
8
use ipnet:: IpNet ;
9
9
use log:: { debug, info} ;
10
10
use regex:: Regex ;
11
11
use reqwest:: blocking:: Client ;
12
- use reqwest:: header:: AUTHORIZATION ;
13
12
use serde:: Deserialize ;
14
- use std:: collections:: HashMap ;
15
13
use std:: fs:: create_dir_all;
16
14
use std:: io:: Write ;
17
15
use std:: net:: { IpAddr , SocketAddr } ;
18
16
use std:: str:: FromStr ;
19
17
20
- impl Mullvad {
21
- fn upload_wg_key ( client : & Client , auth_token : & str , keypair : & WgKey ) -> anyhow:: Result < ( ) > {
22
- let mut map = HashMap :: new ( ) ;
23
- map. insert ( "pubkey" , keypair. public . clone ( ) ) ;
24
- client
25
- . post ( "https://api.mullvad.net/www/wg-pubkeys/add/" )
26
- . header ( AUTHORIZATION , format ! ( "Token {auth_token}" ) )
27
- . json ( & map)
28
- . send ( ) ?
29
- . error_for_status ( )
30
- . context ( "Failed to upload keypair to Mullvad" ) ?;
31
- info ! (
32
- "Public key submitted to Mullvad. Private key will be saved in generated config files."
33
- ) ;
34
- Ok ( ( ) )
35
- }
36
- }
37
-
38
18
impl WireguardProvider for Mullvad {
39
19
fn create_wireguard_config ( & self , uiclient : & dyn UiClient ) -> anyhow:: Result < ( ) > {
40
20
let wireguard_dir = self . wireguard_dir ( ) ?;
@@ -47,46 +27,15 @@ impl WireguardProvider for Mullvad {
47
27
. send ( ) ?
48
28
. json ( ) . with_context ( || "Failed to parse Mullvad relays response - try again after a few minutes or report an issue if it is persistent" ) ?;
49
29
50
- let username = self . request_mullvad_username ( uiclient) ?;
51
- let auth: AuthToken = client
52
- . get ( format ! ( "https://api.mullvad.net/www/accounts/{username}/" ) )
53
- . send ( ) ?
54
- . json ( ) ?;
55
-
56
- let user_info: UserResponse = client
57
- . get ( "https://api.mullvad.net/www/me/" )
58
- . header ( AUTHORIZATION , format ! ( "Token {}" , auth. auth_token) )
59
- . send ( ) ?
60
- . json ( ) ?;
61
-
62
- let user_info = user_info. account ;
63
- debug ! ( "Received user info: {:?}" , user_info) ;
64
-
65
- let keypair: WgKey = prompt_for_wg_key ( user_info, & client, & auth. auth_token , uiclient) ?;
30
+ let ( keypair, ipv4_net, ipv6_net) = prompt_for_wg_key ( uiclient) ?;
66
31
67
32
debug ! ( "Chosen keypair: {:?}" , keypair) ;
68
- // Get user info again in case we uploaded new key
69
- let user_info: UserResponse = client
70
- . get ( "https://api.mullvad.net/www/me/" )
71
- . header ( AUTHORIZATION , format ! ( "Token {}" , auth. auth_token) )
72
- . send ( ) ?
73
- . json ( ) ?;
74
-
75
- let user_info = user_info. account ;
76
- let wg_peer = user_info
77
- . wg_peers
78
- . iter ( )
79
- . find ( |x| x. key . public == keypair. public )
80
- . ok_or_else ( || anyhow ! ( "Did not find key: {} in Mullvad account" , keypair. public) ) ?;
81
33
82
34
// TODO: Hardcoded IP - can we scrape this anywhere?
83
35
let dns = std:: net:: Ipv4Addr :: new ( 193 , 138 , 218 , 74 ) ;
84
36
let interface = WireguardInterface {
85
37
private_key : keypair. private . clone ( ) ,
86
- address : vec ! [
87
- IpNet :: from( wg_peer. ipv4_address) ,
88
- IpNet :: from( wg_peer. ipv6_address) ,
89
- ] ,
38
+ address : vec ! [ ipv4_net, ipv6_net] ,
90
39
dns : Some ( vec ! [ IpAddr :: from( dns) ] ) ,
91
40
} ;
92
41
@@ -162,7 +111,6 @@ struct WireguardRelay {
162
111
ipv6_addr_in : std:: net:: Ipv6Addr ,
163
112
pubkey : String ,
164
113
multihop_port : u16 ,
165
- socks_name : String ,
166
114
}
167
115
168
116
struct Devices {
@@ -188,69 +136,48 @@ impl ConfigurationChoice for Devices {
188
136
}
189
137
}
190
138
191
- fn prompt_for_wg_key (
192
- user_info : UserInfo ,
193
- client : & Client ,
194
- auth_token : & str ,
195
- uiclient : & dyn UiClient ,
196
- ) -> anyhow:: Result < WgKey > {
197
- if !user_info. wg_peers . is_empty ( ) {
198
- let existing = Devices { devices : user_info. wg_peers . clone ( ) } ;
199
-
200
- let selection = uiclient. get_configuration_choice ( & existing) ?;
201
-
202
- if selection >= user_info. wg_peers . len ( ) {
203
- if user_info. wg_peers . len ( ) >= user_info. max_wg_peers as usize
204
- || !user_info. can_add_wg_peers
205
- {
206
- return Err ( anyhow ! ( "Cannot add more Wireguard keypairs to this account. Try to delete existing keypairs." ) ) ;
207
- }
208
- let keypair = generate_keypair ( ) ?;
209
- Mullvad :: upload_wg_key ( client, auth_token, & keypair) ?;
210
- Ok ( keypair)
211
- } else {
212
- let pubkey_clone = user_info. wg_peers [ selection] . key . public . clone ( ) ;
213
- let private_key = uiclient. get_input ( Input {
214
- prompt : format ! ( "Private key for {}" ,
215
- & user_info. wg_peers[ selection] . key. public
216
- ) ,
217
- validator : Some ( Box :: new ( move |private_key : & String | -> Result < ( ) , String > {
218
-
219
- let private_key = private_key. trim ( ) ;
220
-
221
- if private_key. len ( ) != 44 {
222
- return Err ( "Expected private key length of 44 characters" . to_string ( )
223
- ) ;
224
- }
225
-
226
- match generate_public_key ( private_key) {
227
- Ok ( public_key) => {
228
- if public_key != pubkey_clone {
229
- return Err ( "Private key does not match public key" . to_string ( ) ) ;
230
- }
231
- Ok ( ( ) )
139
+ fn prompt_for_wg_key ( uiclient : & dyn UiClient ) -> anyhow:: Result < ( WgKey , IpNet , IpNet ) > {
140
+ // TODO: We could also generate new private key first - generate_keypair()
141
+ let private_key = uiclient. get_input ( Input {
142
+ prompt : "Enter your Wireguard Private key and upload the Public Key as a Mullvad device"
143
+ . to_owned ( ) ,
144
+ validator : Some ( Box :: new (
145
+ move |private_key : & String | -> Result < ( ) , String > {
146
+ let private_key = private_key. trim ( ) ;
147
+
148
+ if private_key. len ( ) != 44 {
149
+ Err ( "Expected private key length of 44 characters" . to_string ( ) )
150
+ } else {
151
+ Ok ( ( ) )
232
152
}
233
- Err ( _) => Err ( "Failed to generate public key" . to_string ( ) )
234
- } } ) ) } ) ?;
153
+ } ,
154
+ ) ) ,
155
+ } ) ?;
235
156
157
+ let ipv4_address = IpNet :: from_str ( & uiclient. get_input ( Input {
158
+ prompt : "Enter the IPv4 address range Mullvad returned after adding the device" . to_owned ( ) ,
159
+ validator : Some ( Box :: new ( move |_ip : & String | -> Result < ( ) , String > {
160
+ // TODO: Ipv4 range validator
161
+ Ok ( ( ) )
162
+ } ) ) ,
163
+ } ) ?) ?;
236
164
237
- Ok ( WgKey {
238
- public : user_info. wg_peers [ selection] . key . public . clone ( ) ,
239
- private : private_key,
240
- } )
241
- }
242
- } else if uiclient. get_bool_choice ( BoolChoice {
243
- prompt :
244
- "No Wireguard keys currently exist on your Mullvad account, would you like to generate a new keypair?" . to_string ( ) ,
245
- default : true ,
246
- } ) ?
247
- {
248
- let keypair = generate_keypair ( ) ?;
249
- Mullvad :: upload_wg_key ( client, auth_token, & keypair) ?;
250
- Ok ( keypair)
251
- } else {
252
- Err ( anyhow ! ( "Wireguard requires a keypair, either upload one to Mullvad or let vopono generate one" ) )
253
- }
165
+ let ipv6_address = IpNet :: from_str ( & uiclient. get_input ( Input {
166
+ prompt : "Enter the IPv6 address range Mullvad returned after adding the device" . to_owned ( ) ,
167
+ validator : Some ( Box :: new ( move |_ip : & String | -> Result < ( ) , String > {
168
+ // TODO: Ipv4 range validator
169
+ Ok ( ( ) )
170
+ } ) ) ,
171
+ } ) ?) ?;
172
+
173
+ Ok ( (
174
+ WgKey {
175
+ public : generate_public_key ( & private_key) . expect ( "Failed to generate public key" ) ,
176
+ private : private_key,
177
+ } ,
178
+ ipv4_address,
179
+ ipv6_address,
180
+ ) )
254
181
}
255
182
256
183
fn request_port ( uiclient : & dyn UiClient ) -> anyhow:: Result < u16 > {
0 commit comments