We prefer the noun 'normalized_hostname' because we are interested
in the return value of the function, not the way in which it alters
the state of the program.
The hostname validation checks as much as it can. This serves its
purpose as a preliminary check to avoid a roundtrip to the Nord API.
... | ... |
@@ -40,9 +40,13 @@ async def _get(endpoint): |
40 | 40 |
return resp |
41 | 41 |
|
42 | 42 |
|
43 |
-def _normalize_hostname(hostname): |
|
44 |
- if not hostname.endswith('nordvpn.com'): |
|
45 |
- return f'{hostname}.nordvpn.com' |
|
43 |
+def normalized_hostname(hostname): |
|
44 |
+ """Return the fully qualified domain name of a NordVPN host.""" |
|
45 |
+ host, *domain = hostname.split('.') |
|
46 |
+ if not domain: |
|
47 |
+ return f'{host}.nordvpn.com' |
|
48 |
+ elif tuple(domain) != ('nordvpn', 'com'): |
|
49 |
+ raise ValueError(f'invalid NordVPN host {hostname}') |
|
46 | 50 |
return hostname |
47 | 51 |
|
48 | 52 |
|
... | ... |
@@ -68,7 +72,7 @@ async def host_config(host, protocol='tcp'): |
68 | 72 |
the trailing '.nordvpn.com'. |
69 | 73 |
protocol: str, 'tcp' or 'udp' |
70 | 74 |
""" |
71 |
- host = _normalize_hostname(host) |
|
75 |
+ host = normalized_hostname(host) |
|
72 | 76 |
resp = await _get(f'files/download/{_config_filename(host, protocol)}') |
73 | 77 |
return await resp.text() |
74 | 78 |
|
... | ... |
@@ -90,7 +94,7 @@ async def host_load(host=None): |
90 | 94 |
to percentage load. |
91 | 95 |
""" |
92 | 96 |
if host: |
93 |
- host = _normalize_hostname(host) |
|
97 |
+ host = normalized_hostname(host) |
|
94 | 98 |
endpoint = f'server/stats/{host}' if host else 'server/stats' |
95 | 99 |
resp = await _get(endpoint) |
96 | 100 |
resp = await resp.json() |
... | ... |
@@ -128,3 +132,17 @@ async def dns_servers(): |
128 | 132 |
"""Return a list of ip addresses of NordVPN DNS servers.""" |
129 | 133 |
resp = await _get('dns/smart') |
130 | 134 |
return await resp.json() |
135 |
+ |
|
136 |
+ |
|
137 |
+async def valid_credentials(username, password): |
|
138 |
+ """Return True if NordVPN accepts the username/password combination. |
|
139 |
+ |
|
140 |
+ Sometimes connecting to the VPN server gives an authentication error even |
|
141 |
+ if the correct credentials are given. This function is useful to first verify |
|
142 |
+ credentials so as to avoid unecessary reconnection attempts. |
|
143 |
+ |
|
144 |
+ Parameters |
|
145 |
+ ---------- |
|
146 |
+ username, password : str |
|
147 |
+ """ |
|
148 |
+ return True |