Skip to content

Commit

Permalink
Merge pull request #156 from ivankudinov-termius/release/1.2.13
Browse files Browse the repository at this point in the history
Release/1.2.13
  • Loading branch information
Maxbey authored Nov 30, 2020
2 parents efbc89a + 22d5a77 commit 7d7d3e6
Show file tree
Hide file tree
Showing 32 changed files with 339 additions and 129 deletions.
3 changes: 1 addition & 2 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
[bumpversion]
current_version = 1.2.12
current_version = 1.2.13
commit = True
tag = True

[bumpversion:file:termius/__init__.py]

2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ python:
- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
install:
- git clone https://github.com/sstephenson/bats.git && cd bats && ./install.sh .. && cd -
- sudo apt-get install pandoc
Expand Down
8 changes: 4 additions & 4 deletions contrib/completion/bash/termius
Original file line number Diff line number Diff line change
Expand Up @@ -217,17 +217,17 @@ _termius()
cmds_groups_arg_options='-f --format -c --column --max-width --log-file'
cmds_groups_file_options='--log-file'
cmds_help='-h --help'
cmds_host='-h --help --log-file -t --tag -g --group -a --address -p --port -s --snippet --identity -u --username -P --password -i --identity-file -d --delete -L --label -S --strict-host-key-check -T --timeout --use-ssh-key -k --keep-alive-packages'
cmds_host_arg_options='--log-file -t --tag -g --group -a --address -p --port -s --snippet --identity -u --username -P --password -i --identity-file -L --label -S --strict-host-key-check -T --timeout --use-ssh-key -k --keep-alive-packages'
cmds_host='-h --help --log-file -t --tag -g --group -a --address -p --port -s --snippet --identity -u --username -i --identity-file -d --delete -L --label -S --strict-host-key-check -T --timeout --use-ssh-key -k --keep-alive-packages'
cmds_host_arg_options='--log-file -t --tag -g --group -a --address -p --port -s --snippet --identity -u --username -i --identity-file -L --label -S --strict-host-key-check -T --timeout --use-ssh-key -k --keep-alive-packages'
cmds_host_file_options='--log-file -i --identity-file'
cmds_hosts='-h --help -f --format -c --column --max-width --noindent --quote --log-file -t --tag -g --group'
cmds_hosts_arg_options='-f --format -c --column --max-width --log-file -t --tag -g --group'
cmds_hosts_file_options='--log-file'
cmds_identities='-h --help -f --format -c --column --max-width --noindent --quote --log-file'
cmds_identities_arg_options='-f --format -c --column --max-width --log-file'
cmds_identities_file_options='--log-file'
cmds_identity='-h --help --log-file -u --username -p --password -i --identity-file -k --ssh-key -d --delete -L --label'
cmds_identity_arg_options='--log-file -u --username -p --password -i --identity-file -k --ssh-key -L --label'
cmds_identity='-h --help --log-file -u --username -i --identity-file -k --ssh-key -d --delete -L --label'
cmds_identity_arg_options='--log-file -u --username -i --identity-file -k --ssh-key -L --label'
cmds_identity_file_options='--log-file -i --identity-file'
cmds_info='-h --help --log-file -G --group -H --host -M --no-merge -f --format -c --column --prefix --noindent --address --max-width'
cmds_info_arg_options='--log-file -f --format -c --column --prefix --address'
Expand Down
19 changes: 16 additions & 3 deletions dev-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
# Copyright (c) 2020 Termius Corporation.
# dev-requirements.txt

mock
nose
pytest
pytest-cov
coverage
prospector[with_pyroma]==1.1.6.2
pyflakes==1.6.0
pyroma==2.0
paver
bumpversion
pypandoc
pygments

pytest; python_version != "3.5"
pytest>=4.6; python_version == "3.5"

prospector[with_pyroma]==1.3; python_version >= "3.7"
prospector[with_pyroma]==1.2; python_version == "3.6"
prospector[with_pyroma]==1.1.6.2; python_version <= "3.5"

pyflakes==2.2.0; python_version >= "3.7"
pyflakes==1.6.0; python_version < "3.7"

cryptography==3.0; python_version == "3.5"
cryptography==2.9; python_version == "2.7"
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get_long_description():
version=__version__,
license='BSD',
author='Termius Corporation',
author_email='[email protected].com',
author_email='[email protected]',
url='https://github.com/termius/termius-cli',
description='Termius ssh-config utility.',
long_description=get_long_description(),
Expand All @@ -86,8 +86,11 @@ def get_long_description():
'License :: OSI Approved :: BSD License',
'Operating System :: Unix',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Topic :: Utilities',
],
entry_points={
Expand Down
2 changes: 1 addition & 1 deletion termius/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package with CLI tool and API."""
__version__ = '1.2.12'
__version__ = '1.2.13'
2 changes: 0 additions & 2 deletions termius/cloud/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ def extend_parser(self, parser):
@abc.abstractmethod
def process_sync(self, api_controller):
"""Do sync staff here."""
pass

# pylint: disable=no-self-use
def prompt_authy_token(self):
Expand Down Expand Up @@ -146,7 +145,6 @@ def extend_parser(self, parser):

def process_sync(self, api_controller):
"""Do sync staff here."""
pass

def take_action(self, parsed_args):
"""Process decrypt and encrypt text."""
Expand Down
41 changes: 27 additions & 14 deletions termius/core/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import six
import requests
from requests.auth import AuthBase
from .exceptions import AuthyTokenIssue
from .exceptions import AuthyTokenIssue, OutdatedVersion


# pylint: disable=too-few-public-methods
Expand Down Expand Up @@ -68,21 +68,34 @@ def login(self, email, password, authy_token=None):
if authy_token is not None:
payload['authy_token'] = authy_token

response = requests.post(
self.request_url('v3.1/login/'), data=payload
)
if response.status_code == 487:
raise AuthyTokenIssue(response.json)
if response.status_code != 200:
self.logger.warning('Can not login!\nResponse %s', response.text)

assert response.status_code == 200
response = requests.post(self.request_url('v3.1/login/'), data=payload)
self.__check_login_response(response)

response_payload = response.json()
apikey = response_payload['token']
self.set_auth(email, apikey)
return response_payload

def __check_login_response(self, response):
if response.status_code == 487:
raise AuthyTokenIssue(response.json)

if response.status_code != 200:
self.logger.warning('Can not login!')

self.__check_response(response, (200,))

@staticmethod
def __check_response(response, success_statuses=None):
if response.status_code == 490:
raise OutdatedVersion(
'The current version of Termius CLI is '
'incompatible with new Termius encryption algorithms.'
)

success_statuses = success_statuses or (200, 201, 202, 204)
assert response.status_code in success_statuses, response.text

def post(self, endpoint, data):
"""Send authorized post request."""
self.logger.debug('send post')
Expand All @@ -92,7 +105,7 @@ def post(self, endpoint, data):
timeout=self.timeout
)
self.logger.debug('get response = %s', response.status_code)
assert response.status_code == 201, response.text
self.__check_response(response, (201,))

return response.json()

Expand All @@ -103,13 +116,13 @@ def get(self, endpoint):
auth=self.auth,
timeout=self.timeout
)
assert response.status_code == 200, response.text
self.__check_response(response, (200,))
return response.json()

def delete(self, endpoint):
"""Send authorized delete request."""
response = requests.delete(self.request_url(endpoint), auth=self.auth)
assert response.status_code in (200, 204)
self.__check_response(response, (200, 204))
return response.json()

def put(self, endpoint, data):
Expand All @@ -119,5 +132,5 @@ def put(self, endpoint, data):
json=data, auth=self.auth,
timeout=self.timeout
)
assert response.status_code in (200, 202), response.text
self.__check_response(response, (200, 202))
return response.json()
6 changes: 2 additions & 4 deletions termius/core/commands/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,14 +202,12 @@ def update_instance(self, args, instance):
# pylint: disable=no-self-use,unused-argument
def pre_save(self, instance):
"""Patch instance fields before saving."""
pass

def update_children(self, instance, args):
"""Update children of instance.
It's called while create and update instance.
"""
pass

def delete_instance(self, instance):
"""Delete model entry."""
Expand All @@ -230,11 +228,11 @@ def log_delete(self, entry):
self._general_log(entry, 'Entry deleted.')

def _general_log(self, entry, message):
self.log.info(message)

if os.getenv('TERMIUS_CLI_DEBUG'):
self.app.stdout.write('{}\n'.format(entry.id))

self.log.info(message)


class GroupStackGetterMixin(object):
"""Mixin to get whole stack of parent groups."""
Expand Down
4 changes: 4 additions & 0 deletions termius/core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,7 @@ class OptionNotSetException(TermiusException):

class AuthyTokenIssue(TermiusException):
"""Raise it when API error caused by `authy_token`."""


class OutdatedVersion(TermiusException):
"""Raise it when API error caused by 490 HTTP status code."""
10 changes: 9 additions & 1 deletion termius/core/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,22 @@ def __init__(self, *args, **kwargs):
# The simplest way to make lint not raise
# access-member-before-definition
self.remote_instance = None
super(Model, self).__init__(*args, **kwargs)

# Do not store extra fields for security reason
fields = self.__filter_fields(kwargs)
super(Model, self).__init__(*args, **fields)

is_need_to_patch_remote = (
self.remote_instance and
not isinstance(self.remote_instance, RemoteInstance)
)
if is_need_to_patch_remote:
self.remote_instance = RemoteInstance(self.remote_instance)

@classmethod
def __filter_fields(cls, fields):
return {k: v for k, v in fields.items() if k in cls.allowed_fields()}

@classmethod
def fk_field_names(cls):
"""Return name list for relation fields."""
Expand Down
6 changes: 2 additions & 4 deletions termius/core/models/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ class SshKey(Model):

fields = {
'label': Field(str, False, ''),
'passphrase': Field(str, False, ''),
'private_key': Field(str, False, ''),
'public_key': Field(str, False, ''),
}
Expand All @@ -51,13 +50,12 @@ class Identity(Model):
fields = {
'label': Field(str, False, ''),
'username': Field(str, False, ''),
'password': Field(str, False, ''),
'is_visible': Field(str, False, False),
'ssh_key': Field(SshKey, False, None),
}
mergable_fields = {'username', 'password', 'ssh_key'}
mergable_fields = {'username', 'ssh_key'}
set_name = 'identity_set'
crypto_fields = {'label', 'username', 'password'}
crypto_fields = {'label', 'username'}


class SshConfig(Model):
Expand Down
2 changes: 1 addition & 1 deletion termius/core/storage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,6 @@ def make_strategy(self, strategy_class, default):
def _validate_the_single_model(self, founded_models):
if not founded_models:
raise DoesNotExistException
elif len(founded_models) != 1:
if len(founded_models) != 1:
raise TooManyEntriesException
return founded_models[0]
1 change: 0 additions & 1 deletion termius/core/storage/strategies.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ def delete(self, model):

def remove_intersection(self, deleted_sets):
"""Confirm delete (Need to create more suitable description)."""
pass


class SoftDeleteStrategy(DeleteStrategy):
Expand Down
2 changes: 1 addition & 1 deletion termius/formatters/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def render_command(self, ssh_config, address, ssh_key_file, pfrule=None):
"""Generate ssh command call."""
identity = ssh_config.get('identity', dict())
username = identity.get('username', '')
return ' '.join([i for i in[
return ' '.join([i for i in [
'ssh',
format_port(ssh_config['port']),
format_identity_file(ssh_key_file),
Expand Down
6 changes: 1 addition & 5 deletions termius/handlers/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class IdentityCommand(SshKeyGeneratorMixin, DetailCommand):
def fields(self):
"""Return dictionary of args serializers to models field."""
_fields = {
i: attrgetter(i) for i in ('label', 'username', 'password')
i: attrgetter(i) for i in ('label', 'username')
}
_fields['ssh_key'] = self.get_ssh_key_field
_fields['is_visible'] = partial(truth)
Expand Down Expand Up @@ -49,10 +49,6 @@ def extend_parser(self, parser):
'-u', '--username',
metavar='USERNAME', help='username for ssh authentication'
)
parser.add_argument(
'-p', '--password',
metavar='PASSWORD', help='password for ssh authentication'
)
parser.add_argument(
'-i', '--identity-file',
metavar='FILE', help='select FILE as private key'
Expand Down
2 changes: 0 additions & 2 deletions termius/handlers/pf_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ class PFRulesCommand(ListCommand):
class InvalidBinding(InvalidArgumentException):
"""Raise it when binding can not be parsed."""

pass


class BindingParser(object):
"""Binding string parser.
Expand Down
2 changes: 1 addition & 1 deletion termius/handlers/ssh_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(self, command):
def fields(self):
"""Return dictionary of args serializers to models field."""
_fields = {
i: attrgetter(i) for i in ('username', 'password')
i: attrgetter(i) for i in ('username',)
}
_fields['ssh_key'] = self.get_ssh_key_field
_fields['is_visible'] = partial(not_)
Expand Down
18 changes: 6 additions & 12 deletions termius/porting/providers/securecrt/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ def __init__(self, xml):

def parse_hosts(self):
"""Parse SecureCRT Sessions."""
sessions = self.get_element_by_name(
self.xml.getchildren(), 'Sessions'
).getchildren()
sessions = list(self.get_element_by_name(list(self.xml), 'Sessions'))

self.parse_sessions(sessions, self.tree)

Expand All @@ -35,26 +33,22 @@ def parse_sessions(self, sessions, parent_node):
else:
parent_node[session.get('name')] = {'__group': True}
self.parse_sessions(
session.getchildren(),
list(session),
parent_node[session.get('name')]
)

def is_session_group(self, session):
"""Check node element type."""
return self.get_element_by_name(
session.getchildren(), 'Hostname'
) is None
return self.get_element_by_name(list(session), 'Hostname') is None

def parse_identity(self):
"""Parse SecureCRT SSH2 raw key."""
identity = self.get_element_by_name(
self.xml.getchildren(), 'SSH2'
)
identity = self.get_element_by_name(list(self.xml), 'SSH2')
if identity is None:
return None

identity_filename = self.get_element_by_name(
identity.getchildren(),
list(identity),
'Identity Filename V2'
)

Expand All @@ -78,7 +72,7 @@ def parse_identity(self):

def make_host(self, session):
"""Adapt SecureCRT Session to Termius host."""
session_attrs = session.getchildren()
session_attrs = list(session)

hostname = self.get_element_by_name(session_attrs, 'Hostname')
port = self.get_element_by_name(session_attrs, '[SSH2] Port')
Expand Down
Loading

0 comments on commit 7d7d3e6

Please sign in to comment.