Passed
Pull Request — master (#69)
by
unknown
01:06
created

nextcloud.session.Session._set_credentials()   B

Complexity

Conditions 8

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 11
dl 0
loc 13
rs 7.3333
c 0
b 0
f 0
cc 8
nop 4
1
# -*- coding: utf-8 -*-
2
from functools import wraps
3
import requests
4
from .compat import encode_requests_password
5
6
import logging
7
_logger = logging.getLogger(__name__)
8
9
10
class NextCloudConnectionError(Exception):
11
    """ A connection error occurred """
12
13
class NextCloudLoginError(Exception):
14
    """ A login error occurred """
15
16
def catch_connection_error(func):
17
18
    @wraps(func)
19
    def wrapper(*args, **kwargs):
20
        try:
21
            return func(*args, **kwargs)
22
        except requests.RequestException as e:
23
            raise NextCloudConnectionError(
24
                'Failed to establish connection to NextCloud', getattr(e.request, 'url', None), e)
25
26
    return wrapper
27
28
29
class Session(object):
30
    """ Session for requesting """
31
32
    def __init__(self, url=None, user=None, password=None, auth=None, session_kwargs=None):
33
        self.session = None
34
        self.auth = None
35
        self.user = None
36
        self._set_credentials(user, password, auth)
37
        self.url = url.rstrip('/')
38
        self._session_kwargs = session_kwargs or {}
39
40
    def _set_credentials(self, user, password, auth):
41
        if auth:
42
            self.auth = auth
43
        if user:
44
            self.user = user
45
        else:
46
            if isinstance(self.auth, tuple):
47
                self.user = self.auth[0]
48
            else:
49
                if isinstance(self.auth, requests.auth.AuthBase):
50
                    self.user = self.auth.username
51
        if not self.auth and (self.user and password):
52
            self.auth = (self.user, encode_requests_password(password))
53
54
    def request(self, method, url, **kwargs):
55
        if self.session:
56
            return self.session.request(method=method, url=url, **kwargs)
57
        else:
58
            _kwargs = self._session_kwargs
59
            _kwargs.update(kwargs)
60
            if not kwargs.get('auth', False):
61
                _kwargs['auth'] = self.auth
62
            return requests.request(method, url, **_kwargs)
63
64
    def login(self, user=None, password=None, auth=None, client=None):
65
        """Create a stable session on the server.
66
67
        :param user_id: user id
68
        :param password: password
69
        :param auth: object for any auth method
70
        :param client: object for any auth method
71
        :raises: HTTPResponseError in case an HTTP error status was returned
72
        """
73
        self.session = requests.Session()
74
        for k in self._session_kwargs:
75
            setattr(self.session, k, self._session_kwargs[k])
76
77
        self._set_credentials(user, password, auth)
78
        self.session.auth = self.auth
79
        if client:
80
            self._check_session(client.with_attr(json_output=True), retry=3)
81
82
83
    def _check_session(self, client=None, retry=None):
84
        def _clear():
85
            if self.session:
86
                self.logout()
87
88
        def _raise(e):
89
            if retry:
90
                _logger.warning('Retry session check (%s)', self.url)
91
                return self._check_session(client, retry=retry - 1)
92
            else:
93
                _clear()
94
                raise e
95
96
        try:
97
            resp = client.get_user()
98
            if not resp.is_ok:
99
                _raise(NextCloudLoginError(
100
                        'Failed to login to NextCloud', self.url, resp))
101
        except requests.exceptions.SSLError as e:
102
            _raise(e)
103
        except NextCloudConnectionError as e:
104
            _raise(e)
105
        except Exception as e:
106
            _clear()
107
            raise e
108
109
    def logout(self):
110
        """Log out the authenticated user and close the session.
111
112
        :returns: True if the operation succeeded, False otherwise
113
        :raises: HTTPResponseError in case an HTTP error status was returned
114
        """
115
        self.session.close()
116
        self.session = None
117
        return True
118