Skip to content
This repository has been archived by the owner on Jan 6, 2022. It is now read-only.

Commit

Permalink
Initial pypi packaging
Browse files Browse the repository at this point in the history
  • Loading branch information
chadsr committed Sep 13, 2017
1 parent 3a35482 commit 0795148
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 75 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
nordnm/__pycache__/
*.pyc
dist/
*.egg-info
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# NordVPN-NetworkManager
# NordNM

This tool removes the need for manually handling OpenVPN configurations from NordVPN. It will synchronise the best servers from chosen countries into the NetworkManager VPN list. A synchronised VPN can then be chosen to auto-connect to, whenever NetworkManager brings an network connection up.

More documentation will be available when this repository is ready for public use.
More documentation will be available when this tool is out of Alpha releases.

**Warning:**
*This tool is still highly experimental and is definitely not yet robust enough to use reliably. I take no responsibility for any unforseen problems it may cause.*
*This tool is still highly under development and is not yet robust enough to use reliably. I take no responsibility for any unforseen problems it may cause.*

## Features:
- Uses the latest NordVPN OpenVPN configuration files.
Expand All @@ -17,29 +17,35 @@ More documentation will be available when this repository is ready for public us
- Disables IPv6 by default, to avoid IPv6 leaks.
- Sets the auto connect server of your choice for all NetworkManager connections, instead of per connection. (optional)

## Requirements
### System
#### Debian/Ubuntu
## 1. Requirements

### Debian/Ubuntu
```
sudo apt update && sudo apt install openvpn network-manager-openvpn-gnome
sudo apt update && sudo apt install openvpn network-manager network-manager-gnome network-manager-openvpn-gnome
```
#### Arch

### Arch

```
sudo pacman -S openvpn networkmanager-openvpn
sudo pacman -S networkmanager openvpn networkmanager-openvpn
```

### Python
## 2. Installation

```
sudo -H pip3 install -r requirements.txt
sudo -H pip3 install nordnm
```

## Usage Examples
*get the latest configs, synchronise and then select auto-connect server:*
## 3. Usage Examples

*Get the latest configs, synchronise and then select a "normal" Netherlands server using tcp as auto-connect server:*

```
sudo python3 nordnm --update --sync --auto-connect nl normal tcp
sudo nordnm --update --sync --auto-connect nl normal tcp
```

*View descriptions of other options:*

```
sudo python3 nordnm --help
sudo nordnm --help
```
3 changes: 2 additions & 1 deletion nordnm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
__version__ = "0.1"
__package__ = "nordnm"
__version__ = "0.0a10"
__license__ = "GNU General Public License v3 or later (GPLv3+)"
15 changes: 8 additions & 7 deletions nordnm/__main__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#!/usr/bin/env python3

from nordnm import NordNM
from nordnm import nordnm
import sys
import logging
import os


def main(argv):
NordNM()


if __name__ == "__main__":
def main():
if os.getuid() != 0:
print("This script must be run as root! Exiting.")
sys.exit(1)

logging.basicConfig(format='[%(levelname)s] [%(name)s]: %(message)s', level=logging.INFO, stream=sys.stdout)
main(sys.argv)

nordnm.NordNM()


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions nordnm/benchmarking.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import utils
import nordapi
from nordnm import utils
from nordnm import nordapi

import multiprocessing
from functools import partial
Expand Down
4 changes: 2 additions & 2 deletions nordnm/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import utils
import nordapi
from nordnm import utils
from nordnm import nordapi

import configparser
import logging
Expand Down
2 changes: 1 addition & 1 deletion nordnm/networkmanager.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import utils
from nordnm import utils

import subprocess
import shutil
Expand Down
68 changes: 28 additions & 40 deletions nordnm/nordnm.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from config import ConfigHandler
from credentials import CredentialsHandler
import nordapi
import networkmanager
import utils
import benchmarking
#!/usr/bin/env python3

from nordnm.credentials import CredentialsHandler
from nordnm.config import ConfigHandler
from nordnm import nordapi
from nordnm import networkmanager
from nordnm import utils
from nordnm import benchmarking
from nordnm import paths

import argparse
import os
Expand All @@ -14,18 +17,6 @@
import copy
from timeit import default_timer as timer

# TODO: Terminate script/wait cleanly if network connection goes down

# TODO: Put these paths somewhere more appropriate
HOME_DIR = os.path.expanduser('~' + utils.get_current_user())
USER_DIR = os.path.join(HOME_DIR, '.nordnm/')
OVPN_DIR = os.path.join(USER_DIR, 'configs/')
CONFIG_PATH = os.path.join(USER_DIR, 'settings.conf')

ROOT_DIR = '/usr/share/nordnm/'
ACTIVE_SERVERS_PATH = os.path.join(ROOT_DIR, 'active_servers')
CREDENTIALS_PATH = os.path.join(ROOT_DIR, 'credentials')


class NordNM(object):
def __init__(self):
Expand All @@ -51,15 +42,15 @@ def setup(self):

self.create_directories()

self.config = ConfigHandler(CONFIG_PATH)
self.credentials = CredentialsHandler(CREDENTIALS_PATH)
self.config = ConfigHandler(paths.SETTINGS)
self.credentials = CredentialsHandler(paths.CREDENTIALS)

self.black_list = self.config.get_blacklist()
self.white_list = self.config.get_whitelist()

self.active_servers = {}
if os.path.isfile(ACTIVE_SERVERS_PATH):
self.active_servers = self.load_active_servers(ACTIVE_SERVERS_PATH)
if os.path.isfile(paths.ACTIVE_SERVERS):
self.active_servers = self.load_active_servers(paths.ACTIVE_SERVERS)

def run(self, credentials, update, sync, purge, auto_connect):
updated = False
Expand All @@ -83,23 +74,20 @@ def run(self, credentials, update, sync, purge, auto_connect):
networkmanager.restart()

def create_directories(self):
if not os.path.exists(USER_DIR):
os.mkdir(USER_DIR)
utils.chown_path_to_user(USER_DIR)

if not os.path.exists(OVPN_DIR):
os.mkdir(OVPN_DIR)
utils.chown_path_to_user(OVPN_DIR)
if not os.path.exists(paths.DIR_ROOT):
os.mkdir(paths.DIR_ROOT)
utils.chown_path_to_user(paths.DIR_ROOT)

if not os.path.exists(ROOT_DIR):
os.mkdir(ROOT_DIR)
if not os.path.exists(paths.DIR_OVPN):
os.mkdir(paths.DIR_OVPN)
utils.chown_path_to_user(paths.DIR_OVPN)

def get_configs(self):
self.logger.info("Attempting to download and extract the latest NordVPN configurations.")

configs = nordapi.get_configs()
if configs:
utils.extract_zip(configs, OVPN_DIR)
utils.extract_zip(configs, paths.DIR_OVPN)
else:
self.logger.error("Could not retrieve configs from NordVPN")

Expand All @@ -108,11 +96,11 @@ def get_ovpn_path(self, domain, protocol):
ovpn_path = None

try:
for f in os.listdir(OVPN_DIR):
file_path = os.path.join(OVPN_DIR, f)
for f in os.listdir(paths.DIR_OVPN):
file_path = os.path.join(paths.DIR_OVPN, f)
if os.path.isfile(file_path):
if fnmatch(f, wildcard):
ovpn_path = os.path.join(OVPN_DIR, f)
ovpn_path = os.path.join(paths.DIR_OVPN, f)

except Exception as ex:
self.logger.error(ex)
Expand Down Expand Up @@ -146,7 +134,7 @@ def purge_active_connections(self, remove_autoconnect=True):
networkmanager.remove_connection(connection_name)

del active_servers[key]
self.save_active_servers(active_servers, ACTIVE_SERVERS_PATH) # Save after every successful removal, in case importer is killed abruptly
self.save_active_servers(active_servers, paths.ACTIVE_SERVERS) # Save after every successful removal, in case importer is killed abruptly

self.active_servers = active_servers

Expand All @@ -158,7 +146,7 @@ def purge_active_connections(self, remove_autoconnect=True):

def load_active_servers(self, path):
try:
with open(ACTIVE_SERVERS_PATH, 'rb') as fp:
with open(paths.ACTIVE_SERVERS, 'rb') as fp:
active_servers = pickle.load(fp)
return active_servers
except Exception as ex:
Expand All @@ -167,7 +155,7 @@ def load_active_servers(self, path):

def save_active_servers(self, active_servers, path):
try:
with open(ACTIVE_SERVERS_PATH, 'wb') as fp:
with open(paths.ACTIVE_SERVERS, 'wb') as fp:
pickle.dump(active_servers, fp)
except Exception as ex:
self.logger.error(ex)
Expand Down Expand Up @@ -226,7 +214,7 @@ def connection_exists(self, connection_name):
return False

def configs_exist(self):
configs = os.listdir(OVPN_DIR)
configs = os.listdir(paths.DIR_OVPN)
if configs:
return True
else:
Expand Down Expand Up @@ -280,7 +268,7 @@ def sync_servers(self):
# If the connection already existed, or the import was successful, add the server combination to the active servers
if imported:
self.active_servers[key] = best_servers[key]
self.save_active_servers(self.active_servers, ACTIVE_SERVERS_PATH)
self.save_active_servers(self.active_servers, paths.ACTIVE_SERVERS)

if new_connections > 0:
self.logger.info("%i new connections added.", new_connections)
Expand Down
10 changes: 10 additions & 0 deletions nordnm/paths.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import os
from nordnm import utils

DIR_USERHOME = os.path.expanduser('~' + utils.get_current_user())
DIR_ROOT = os.path.join(DIR_USERHOME, '.nordnm/')
DIR_OVPN = os.path.join(DIR_ROOT, 'configs/')

SETTINGS = os.path.join(DIR_ROOT, 'settings.conf')
ACTIVE_SERVERS = os.path.join(DIR_ROOT, '.active_servers')
CREDENTIALS = os.path.join(DIR_ROOT, 'credentials.conf')
13 changes: 8 additions & 5 deletions nordnm/utils.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import utils

import os
import stat
from io import BytesIO
from zipfile import ZipFile
import subprocess
import logging
import getpass

logger = logging.getLogger(__name__)


# Since we're running with root priveledges, this will return the current username
def get_current_user():
return os.getenv("SUDO_USER")
username = os.getenv("SUDO_USER")
if not username:
username = getpass.getuser()

return username


# Change the owner and group of a given path to the current user
Expand Down Expand Up @@ -80,11 +83,11 @@ def get_rtt_loss(host, ping_attempts):
logger.error("Could not interpret output of ping command.\nOutput: %s", ex)

except subprocess.CalledProcessError:
err = utils.format_std_string(output.stderr)
err = format_std_string(output.stderr)
if err:
logger.error("Ping failed with error: %s", err)
else:
out = utils.format_std_string(output.stdout)
out = format_std_string(output.stdout)
logger.warning("Ping failed with output: %s", out)

return (None, 100) # If anything failed, return rtt as None and 100% loss
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
numpy==1.13.0
requests==2.18.1
numpy>=1.13.0
requests>=2.18.1
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[metadata]
description-file = README.md
license_file = LICENSE
Loading

0 comments on commit 0795148

Please sign in to comment.