Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrated from Docopt to ArgParse #204

Merged
merged 24 commits into from
Jul 4, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
069a112
Ported CLI to argparse, based on functional programming paradigm
calexandru2018 Jun 14, 2020
5017b7c
Ported CLI to argparse, based on OO programming paradigm
calexandru2018 Jun 14, 2020
09753ad
Added descriptive comments
calexandru2018 Jun 14, 2020
7e80254
Updated usage string
calexandru2018 Jun 15, 2020
2b2ad14
Added logging
calexandru2018 Jun 15, 2020
cb290e5
Updated exmaples
calexandru2018 Jun 15, 2020
02c1bd4
Removed function based CLI code
calexandru2018 Jun 17, 2020
e242dba
Removed docopt dependency
calexandru2018 Jun 29, 2020
e813a39
Added usage constant
calexandru2018 Jun 29, 2020
e5af91f
Added back the PVPN_WAIT environment variable
calexandru2018 Jun 29, 2020
dfa4018
Addressed Flake8 issues
calexandru2018 Jun 29, 2020
880efe0
Addressed Flake8 issues
calexandru2018 Jun 29, 2020
455d78c
Addressed Flake8 issues
calexandru2018 Jun 29, 2020
be0391b
Fixed Flake8 issues
calexandru2018 Jul 2, 2020
2d28f96
Fixed Flake8 issues
calexandru2018 Jul 2, 2020
eb77b4e
Fixed Flake8 issues
calexandru2018 Jul 2, 2020
67c68ac
Examples are now inline with the CLI
calexandru2018 Jul 2, 2020
7efe076
Removed unncesessary comment
calexandru2018 Jul 2, 2020
d541079
Cleaned up code and improved readability
calexandru2018 Jul 2, 2020
a0904c0
Removed dependencies still they are no longer needed
calexandru2018 Jul 3, 2020
83bee2c
Updated inline command
calexandru2018 Jul 3, 2020
6057938
Allow uppercase protocol with -p
Rafficer Jul 3, 2020
36cf1ec
Allign help message
Rafficer Jul 3, 2020
204676d
Return missing -p to example
Rafficer Jul 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 117 additions & 71 deletions protonvpn_cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,3 @@
"""
A CLI for ProtonVPN.

Usage:
protonvpn init
protonvpn (c | connect) [<servername>] [-p <protocol>]
protonvpn (c | connect) [-f | --fastest] [-p <protocol>]
protonvpn (c | connect) [--cc <code>] [-p <protocol>]
protonvpn (c | connect) [--sc] [-p <protocol>]
protonvpn (c | connect) [--p2p] [-p <protocol>]
protonvpn (c | connect) [--tor] [-p <protocol>]
protonvpn (c | connect) [-r | --random] [-p <protocol>]
protonvpn (r | reconnect)
protonvpn (d | disconnect)
protonvpn (s | status)
protonvpn configure
protonvpn refresh
protonvpn examples
protonvpn (-h | --help)
protonvpn (-v | --version)

Options:
-f, --fastest Select the fastest ProtonVPN server.
-r, --random Select a random ProtonVPN server.
--cc CODE Determine the country for fastest connect.
--sc Connect to the fastest Secure-Core server.
--p2p Connect to the fastest torrent server.
--tor Connect to the fastest Tor server.
-p PROTOCOL Determine the protocol (UDP or TCP).
-h, --help Show this help message.
-v, --version Display version.

Commands:
init Initialize a ProtonVPN profile.
c, connect Connect to a ProtonVPN server.
r, reconnect Reconnect to the last server.
d, disconnect Disconnect the current session.
s, status Show connection status.
configure Change ProtonVPN-CLI configuration.
refresh Refresh OpenVPN configuration and server data.
examples Print some example commands.

Arguments:
<servername> Servername (CH#4, CH-US-1, HK5-Tor).
"""
# Standard Libraries
import sys
import os
Expand All @@ -51,8 +6,8 @@
import getpass
import shutil
import time
import argparse
# External Libraries
calexandru2018 marked this conversation as resolved.
Show resolved Hide resolved
from docopt import docopt
# protonvpn-cli Functions
from . import connection
from .logger import logger
Expand All @@ -63,7 +18,7 @@
)
# Constants
from .constants import (
CONFIG_DIR, CONFIG_FILE, PASSFILE, USER, VERSION, SPLIT_TUNNEL_FILE
CONFIG_DIR, CONFIG_FILE, PASSFILE, USER, VERSION, SPLIT_TUNNEL_FILE, USAGE
)


Expand All @@ -88,13 +43,54 @@ def cli():
logger.debug("USER: {0}".format(USER))
logger.debug("CONFIG_DIR: {0}".format(CONFIG_DIR))

args = docopt(__doc__, version="ProtonVPN-CLI v{0}".format(VERSION))
logger.debug("Arguments\n{0}".format(str(args).replace("\n", "")))
ProtonVPNCLI()


class ProtonVPNCLI():
def __init__(self):
parser = argparse.ArgumentParser(
prog="protonvpn",
add_help=False
)

parser.add_argument("command", nargs="?")
parser.add_argument("-v", "--version", required=False, action="store_true")
parser.add_argument("-h", "--help", required=False, action="store_true")

args = parser.parse_args(sys.argv[1:2])

logger.debug("Main argument\n{0}".format(args))

if args.version:
print("\nProtonVPN CLI v.{}".format(VERSION))
parser.exit(1)
elif args.command is None or not hasattr(self, args.command) or args.help:
print(USAGE)
parser.exit()

getattr(self, args.command)()

# Intialize ProtonVPN profile
def init(self):
"""Intialiazes ProtonVPN profile. To intialize profile inline, provide the "-i" option."""
parser = argparse.ArgumentParser(description="Initialize ProtonVPN profile", prog="protonvpn init")
parser.add_argument("-i", "--inline", nargs=3, required=False, help="Inline intialize profile. (username password protocol)", metavar="")
calexandru2018 marked this conversation as resolved.
Show resolved Hide resolved

args = parser.parse_args(sys.argv[2:])
logger.debug("Sub-arguments\n{0}".format(args))

if args.i:
print("Inline method invoked")

# Parse arguments
if args.get("init"):
init_cli()
elif args.get("c") or args.get("connect"):
# print(args)

# Connect to VPN
def c(self):
"""Short for connect"""
self.connect()

def connect(self):
check_root()
check_init()

Expand All @@ -106,45 +102,95 @@ def cli():
if int(os.environ.get("PVPN_WAIT", 0)) > 0:
wait_for_network(int(os.environ["PVPN_WAIT"]))

protocol = args.get("-p")
parser = argparse.ArgumentParser(description="Connect to ProtonVPN", prog="protonvpn c")
group = parser.add_mutually_exclusive_group()
group.add_argument("servername", nargs="?", help="Servername (CH#4, CH-US-1, HK5-Tor).", metavar="")
group.add_argument("-f", "--fastest", help="Connect to the fastest ProtonVPN server.", action="store_true")
group.add_argument("-r", "--random", help="Connect to a random ProtonVPN server.", action="store_true")
group.add_argument("--cc", help="Connect to the specified country code (SE, PT, BR, AR).", metavar="")
group.add_argument("--sc", help="Connect to the fastest Secure-Core server.", action="store_true")
group.add_argument("--p2p", help="Connect to the fastest torrent server.", action="store_true")
group.add_argument("--tor", help="Connect to the fastest Tor server.", action="store_true")
parser.add_argument("-p", "--protocol", help="Connect via specified protocol.", choices=["udp", "tcp"], metavar="")
calexandru2018 marked this conversation as resolved.
Show resolved Hide resolved

args = parser.parse_args(sys.argv[2:])
logger.debug("Sub-arguments:\n{0}".format(args))

protocol = args.protocol
if protocol is not None and protocol.lower().strip() in ["tcp", "udp"]:
protocol = protocol.lower().strip()

if args.get("--random"):
if args.random:
connection.random_c(protocol)
elif args.get("--fastest"):
elif args.fastest:
connection.fastest(protocol)
elif args.get("<servername>"):
connection.direct(args.get("<servername>"), protocol)
elif args.get("--cc") is not None:
connection.country_f(args.get("--cc"), protocol)
elif args.servername:
connection.direct(args.servername, protocol)
elif args.cc is not None:
connection.country_f(args.cc, protocol)
# Features: 1: Secure-Core, 2: Tor, 4: P2P
elif args.get("--p2p"):
elif args.p2p:
connection.feature_f(4, protocol)
elif args.get("--sc"):
elif args.sc:
connection.feature_f(1, protocol)
elif args.get("--tor"):
elif args.tor:
connection.feature_f(2, protocol)
else:
connection.dialog()
elif args.get("r") or args.get("reconnect"):

# Reconnect to last connected VPN server
def r(self):
"""Short for reconnect"""
self.reconnect()

def reconnect(self):
check_root()
check_init()
connection.reconnect()
elif args.get("d") or args.get("disconnect"):

# Disconnect from VPN
def d(self):
"""Short for disconnect"""
self.disconnect()

def disconnect(self):
check_root()
check_init()
connection.disconnect()
elif args.get("s") or args.get("status"):

# Display VPN status information
def s(self):
"""Short for status"""
self.status()

def status(self):
connection.status()
elif args.get("configure"):

# Open configurations menu
def cf(self):
"""Short for configure"""
self.configure()

def configure(self):
check_root()
check_init()
configure_cli()
elif args.get("refresh"):

# Refresh servers
def rf(self):
"""Short for refresh"""
self.refresh()

def refresh(self):
check_init()
pull_server_data(force=True)
elif args.get("examples"):

# Show usage examples
def ex(self):
"""Short for examples"""
self.examples()

def examples(self):
print_examples()


Expand Down Expand Up @@ -283,12 +329,12 @@ def print_examples():
" Connect to NO#3 with TCP.\n\n"
"protonvpn c --fastest\n"
" Connect to the fastest VPN Server.\n\n"
"protonvpn connect --cc AU\n"
"protonvpn connect -cc AU\n"
" Connect to the fastest Australian server\n"
" with the default protocol.\n\n"
"protonvpn c --p2p -p tcp\n"
"protonvpn c -p2p -p tcp\n"
" Connect to the fastest torrent server with TCP.\n\n"
"protonvpn c --sc\n"
"protonvpn c -sc\n"
calexandru2018 marked this conversation as resolved.
Show resolved Hide resolved
" Connect to the fastest Secure-Core server with\n"
" the default protocol.\n\n"
"protonvpn reconnect\n"
Expand Down
46 changes: 46 additions & 0 deletions protonvpn_cli/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,49 @@
OVPN_FILE = os.path.join(CONFIG_DIR, "connect.ovpn")
PASSFILE = os.path.join(CONFIG_DIR, "pvpnpass")
VERSION = "2.2.4"

USAGE = """
Official ProtonVPN CLI

Usage:
protonvpn init
protonvpn (c | connect) [<servername>] [-p <protocol>]
protonvpn (c | connect) [-f | --fastest] [-p <protocol>]
protonvpn (c | connect) [--cc <code>] [-p <protocol>]
protonvpn (c | connect) [--sc] [-p <protocol>]
protonvpn (c | connect) [--p2p] [-p <protocol>]
protonvpn (c | connect) [--tor] [-p <protocol>]
protonvpn (c | connect) [-r | --random] [-p <protocol>]
protonvpn (r | reconnect)
protonvpn (d | disconnect)
protonvpn (s | status)
protonvpn (cf | configure)
protonvpn (rf | refresh)
protonvpn (ex | examples)
protonvpn (-h | --help)
protonvpn (-v | --version)

Options:
-f, --fastest Select the fastest ProtonVPN server.
-r, --random Select a random ProtonVPN server.
--cc CODE Determine the country for fastest connect.
--sc Connect to the fastest Secure-Core server.
--p2p Connect to the fastest torrent server.
--tor Connect to the fastest Tor server.
-p PROTOCOL Determine the protocol (UDP or TCP).
-h, --help Show this help message.
-v, --version Display version.

Commands:
init Initialize a ProtonVPN profile.
c, connect Connect to a ProtonVPN server.
r, reconnect Reconnect to the last server.
d, disconnect Disconnect the current session.
s, status Show connection status.
cf, configure Change ProtonVPN-CLI configuration.
rf, refresh Refresh OpenVPN configuration and server data.
ex, examples Print some example commands.

Arguments:
<servername> Servername (CH#4, CH-US-1, HK5-Tor).
"""