Test Failed
Push — master ( 555da9...2798d7 )
by Andreas
48s
created

TpmApi.show_user()   A

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
dl 0
loc 5
rs 9.4285
c 1
b 0
f 0
1
#! /usr/bin/env python
2
"""Team Password Manager API
3
4
To simplify usage of Team Password Manager API.
5
6
You can authenticate with username and password
7
    >>> import tpm
8
    >>> URL = "https://mypasswordmanager.example.com"
9
    >>> USER = 'MyUser'
10
    >>> PASS = 'Secret'
11
    >>> tpmconn = tpm.TpmApiv4(URL, username=USER, password=PASS)
12
13
Or with Private/Public Key
14
    >>> pubkey = '3726d93f2a0e5f0fe2cc3a6e9e3ade964b43b07f897d579466c28b7f8ff51cd0'
15
    >>> privkey = '87324bedead51af96a45271d217b8ad5ef3f220da6c078a9bce4e4318729189c'
16
    >>> tpmconn = tpm.TpmApiv4(URL, private_key=privkey, public_key=pubkey)
17
18
With the connection object you can use all TPM functions, like list all passwords:
19
    >>> tpmconn.list_passwords()
20
21
All API functions from Team Password Manager are included.
22
see http://teampasswordmanager.com/docs/api/
23
24
:copyright: (c) 2017 by Andreas Hubert.
25
:license: The MIT License (MIT), see LICENSE for more details.
26
"""
27
28
__version__ = '3.5'
29
30
import hmac
31
import hashlib
32
import time
33
import requests
34
import re
35
import json
36
import logging
37
from future.standard_library import install_aliases
38
install_aliases()
39
40
from urllib.parse import quote_plus
41
42
# set logger
43
log = logging.getLogger(__name__)
44
# disable unsecure SSL warning
45
requests.packages.urllib3.disable_warnings()
46
47
48
class TPMException(Exception):
49
    pass
50
51
52
class TpmApi(object):
53
    """Settings needed for the connection to Team Password Manager."""
54
    class ConfigError(Exception):
55
        """To throw Exception based on wrong Settings."""
56
        def __init__(self, value):
57
            self.value = value
58
            log.critical(value)
59
60
        def __str__(self):
61
            return repr(self.value)
62
63
    def __init__(self, api, base_url, kwargs):
64
        """init thing."""
65
        # Check if API version is not bullshit
66
        REGEXurl = "^" \
67
                   "(?:(?:https?)://)" \
68
                   "(?:\\S+(?::\\S*)?@)?" \
69
                   "(?:" \
70
                   "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" \
71
                   "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" \
72
                   "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" \
73
                   "|" \
74
                   "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" \
75
                   "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" \
76
                   "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))?" \
77
                   ".?" \
78
                   ")" \
79
                   "(?::\\d{2,5})?" \
80
                   "(?:[/?#]\\S*)?" \
81
                   "$"
82
        self.apiurl = 'api/' + api + '/'
83
        log.debug('Set as apiurl: %s' % self.apiurl)
84
        self.api = self.apiurl
85
        # Check if URL is not bullshit
86
        if re.match(REGEXurl, base_url):
87
            self.base_url = base_url + '/index.php/'
88
            log.debug('Set Base URL to %s' % self.base_url)
89
            self.url = self.base_url + self.apiurl
90
            log.debug('Set URL to %s' % self.url)
91
        else:
92
            raise self.ConfigError('Invalid URL: %s' % base_url)
93
        # set headers
94
        self.headers = {'Content-Type': 'application/json; charset=utf-8',
95
                        'User-Agent': 'tpm.py/' + __version__
96
                        }
97
        log.debug('Set header to %s' % self.headers)
98
        # check kwargs for either keys or user credentials
99
        self.private_key = False
100
        self.public_key = False
101
        self.username = False
102
        self.password = False
103
        self.unlock_reason = False
104
        for key in kwargs:
105
            if key == 'private_key':
106
                self.private_key = kwargs[key]
107
            elif key == 'public_key':
108
                self.public_key = kwargs[key]
109
            elif key == 'username':
110
                self.username = kwargs[key]
111
            elif key == 'password':
112
                self.password = kwargs[key]
113
            elif key == 'unlock_reason':
114
                self.unlock_reason = kwargs[key]
115
        if self.private_key is not False and self.public_key is not False and\
116
                self.username is False and self.password is False:
117
            log.debug('Using Private/Public Key authentication.')
118
        elif self.username is not False and self.password is not False and\
119
                self.private_key is False and self.public_key is False:
120
            log.debug('Using Basic authentication.')
121
        else:
122
            raise self.ConfigError('No authentication specified'
123
                                   ' (user/password or private/public key)')
124
            
125
126
    def request(self, path, action, data=''):
127
        """To make a request to the API."""   
128
        # Check if the path includes URL or not.
129
        if path.startswith(head):
130
            path = path[len(head):]
131
        if not path.startswith(self.api):
132
            path = self.api + path
133
        log.debug('Using path %s' % path)                
134
135
        # If we have data, convert to JSON
136
        if data:
137
            data = json.dumps(data)
138
            log.debug('Data to sent: %s' % data)
139
        # In case of key authentication
140
        if self.private_key and self.public_key:
141
            timestamp = str(int(time.time()))
142
            log.debug('Using timestamp: {}'.format(timestamp))
143
            unhashed = path + timestamp + str(data)
144
            log.debug('Using message: {}'.format(unhashed))
145
            self.hash = hmac.new(str.encode(self.private_key),
146
                                 msg=unhashed.encode('utf-8'),
147
                                 digestmod=hashlib.sha256).hexdigest()
148
            log.debug('Authenticating with hash: %s' % self.hash)
149
            self.headers['X-Public-Key'] = self.public_key
150
            self.headers['X-Request-Hash'] = self.hash
151
            self.headers['X-Request-Timestamp'] = timestamp
152
            auth = False
153
        # In case of user credentials authentication
154
        elif self.username and self.password:
155
            auth = requests.auth.HTTPBasicAuth(self.username, self.password)
156
        # Set unlock reason
157
        if self.unlock_reason:
158
            self.headers['X-Unlock-Reason'] = self.unlock_reason
159
            log.info('Unlock Reason: %s' % self.unlock_reason)
160
        url = head + path
161
        # Try API request and handle Exceptions
162
        try:
163
            if action == 'get':
164
                log.debug('GET request %s' % url)
165
                self.req = requests.get(url, headers=self.headers, auth=auth,
166
                                        verify=False)
167
            elif action == 'post':
168
                log.debug('POST request %s' % url)
169
                self.req = requests.post(url, headers=self.headers, auth=auth,
170
                                         verify=False, data=data)
171
            elif action == 'put':
172
                log.debug('PUT request %s' % url)
173
                self.req = requests.put(url, headers=self.headers,
174
                                        auth=auth, verify=False,
175
                                        data=data)
176
            elif action == 'delete':
177
                log.debug('DELETE request %s' % url)
178
                self.req = requests.delete(url, headers=self.headers,
179
                                           verify=False, auth=auth)
180
181
            if self.req.content == b'':
182
                result = None
183
                log.debug('No result returned.')
184
            else:
185
                result = self.req.json()
186
                if 'error' in result and result['error']:
187
                    raise TPMException(result['message'])
188
189
        except requests.exceptions.RequestException as e:
190
            log.critical("Connection error for " + str(e))
191
            raise TPMException("Connection error for " + str(e))
192
193
        except ValueError as e:
194
            if self.req.status_code == 403:
195
                log.warning(url + " forbidden")
196
                raise TPMException(url + " forbidden")
197
            elif self.req.status_code == 404:
198
                log.warning(url + " forbidden")
199
                raise TPMException(url + " not found")
200
            else:
201
                message = ('%s: %s %s' % (e, self.req.url, self.req.text))
202
                log.debug(message)
203
                raise ValueError(message)
204
205
        return result
206
207
    def post(self, path, data=''):
208
        """For post based requests."""
209
        return self.request(path, 'post', data)
210
211
    def get(self, path):
212
        """For get based requests."""
213
        return self.request(path, 'get')
214
215
    def put(self, path, data=''):
216
        """For put based requests."""
217
        self.request(path, 'put', data)
218
219
    def delete(self, path):
220
        """For delete based requests."""
221
        self.request(path, 'delete')
222
223
    def get_collection(self, path):
224
        """To get pagewise data."""
225
        while True:
226
            items = self.get(path)
227
            req = self.req
228
            for item in items:
229
                yield item
230
            if req.links and req.links['next'] and\
231
                    req.links['next']['rel'] == 'next':
232
                path = req.links['next']['url']
233
            else:
234
                break
235
236
    def collection(self, path):
237
        """To return all items generated by get collection."""
238
        data = []
239
        for item in self.get_collection(path):
240
            data.append(item)
241
        return data
242
243
    # From now on, Functions that work that way in all API Versions.
244
245
    # http://teampasswordmanager.com/docs/api-projects/#list_projects
246
    def list_projects(self):
247
        """List projects."""
248
        log.debug('List all projects.')
249
        return self.collection('projects.json')
250
251
    def list_projects_archived(self):
252
        """List archived projects."""
253
        log.debug('List all archived projects.')
254
        return self.collection('projects/archived.json')
255
256
    def list_projects_favorite(self):
257
        """List favorite projects."""
258
        log.debug('List all favorite projects.')
259
        return self.collection('projects/favorite.json')
260
261
    def list_projects_search(self, searchstring):
262
        """List projects with searchstring."""
263
        log.debug('List all projects with: %s' % searchstring)
264
        return self.collection('projects/search/%s.json' %
265
                               quote_plus(searchstring))
266
267
    def show_project(self, ID):
268
        """Show a project."""
269
        # http://teampasswordmanager.com/docs/api-projects/#show_project
270
        log.debug('Show project info: %s' % ID)
271
        return self.get('projects/%s.json' % ID)
272
273
    def list_passwords_of_project(self, ID):
274
        """List passwords of project."""
275
        # http://teampasswordmanager.com/docs/api-projects/#list_pwds_prj
276
        log.debug('List passwords of project: %s' % ID)
277
        return self.collection('projects/%s/passwords.json' % ID)
278
279
    def list_user_access_on_project(self, ID):
280
        """List users who can access a project."""
281
        # http://teampasswordmanager.com/docs/api-projects/#list_users_prj
282
        log.debug('List User access on project: %s' % ID)
283
        return self.collection('projects/%s/security.json' % ID)
284
285
    def create_project(self, data):
286
        """Create a project."""
287
        # http://teampasswordmanager.com/docs/api-projects/#create_project
288
        log.info('Create project: %s' % data)
289
        NewID = self.post('projects.json', data).get('id')
290
        log.info('Project has been created with ID %s' % NewID)
291
        return NewID
292
293
    def update_project(self, ID, data):
294
        """Update a project."""
295
        # http://teampasswordmanager.com/docs/api-projects/#update_project
296
        log.info('Update project %s with %s' % (ID, data))
297
        self.put('projects/%s.json' % ID, data)
298
299
    def change_parent_of_project(self, ID, NewParrentID):
300
        """Change parent of project."""
301
        # http://teampasswordmanager.com/docs/api-projects/#change_parent
302
        log.info('Change parrent for project %s to %s' % (ID, NewParrentID))
303
        data = {'parent_id': NewParrentID}
304
        self.put('projects/%s/change_parent.json' % ID, data)
305
306
    def update_security_of_project(self, ID, data):
307
        """Update security of project."""
308
        # http://teampasswordmanager.com/docs/api-projects/#update_project_security
309
        log.info('Update project %s security %s' % (ID, data))
310
        self.put('projects/%s/security.json' % ID, data)
311
312
    def archive_project(self, ID):
313
        """Archive a project."""
314
        # http://teampasswordmanager.com/docs/api-projects/#arch_unarch_project
315
        log.info('Archive project %s' % ID)
316
        self.put('projects/%s/archive.json' % ID)
317
318
    def unarchive_project(self, ID):
319
        """Un-Archive a project."""
320
        # http://teampasswordmanager.com/docs/api-projects/#arch_unarch_project
321
        log.info('Unarchive project %s' % ID)
322
        self.put('projects/%s/unarchive.json' % ID)
323
324
    def delete_project(self, ID):
325
        """Delete a project."""
326
        # http://teampasswordmanager.com/docs/api-projects/#delete_project
327
        log.info('Delete project %s' % ID)
328
        self.delete('projects/%s.json' % ID)
329
330
    # http://teampasswordmanager.com/docs/api-passwords/#list_passwords
331
    def list_passwords(self):
332
        """List passwords."""
333
        log.debug('List all passwords.')
334
        return self.collection('passwords.json')
335
336
    def list_passwords_archived(self):
337
        """List archived passwords."""
338
        log.debug('List archived passwords.')
339
        return self.collection('passwords/archived.json')
340
341
    def list_passwords_favorite(self):
342
        """List favorite passwords."""
343
        log.debug('List favorite spasswords.')
344
        return self.collection('passwords/favorite.json')
345
346
    def list_passwords_search(self, searchstring):
347
        """List passwords with searchstring."""
348
        log.debug('List all passwords with: %s' % searchstring)
349
        return self.collection('passwords/search/%s.json' %
350
                               quote_plus(searchstring))
351
352
    def show_password(self, ID):
353
        """Show password."""
354
        # http://teampasswordmanager.com/docs/api-passwords/#show_password
355
        log.info('Show password info: %s' % ID)
356
        return self.get('passwords/%s.json' % ID)
357
358
    def list_user_access_on_password(self, ID):
359
        """List users who can access a password."""
360
        # http://teampasswordmanager.com/docs/api-passwords/#list_users_pwd
361
        log.debug('List user access on password %s' % ID)
362
        return self.collection('passwords/%s/security.json' % ID)
363
364
    def create_password(self, data):
365
        """Create a password."""
366
        # http://teampasswordmanager.com/docs/api-passwords/#create_password
367
        log.info('Create new password %s' % data)
368
        NewID = self.post('passwords.json', data).get('id')
369
        log.info('Password has been created with ID %s' % NewID)
370
        return NewID
371
372
    def update_password(self, ID, data):
373
        """Update a password."""
374
        # http://teampasswordmanager.com/docs/api-passwords/#update_password
375
        log.info('Update Password %s with %s' % (ID, data))
376
        self.put('passwords/%s.json' % ID, data)
377
378
    def update_security_of_password(self, ID, data):
379
        """Update security of a password."""
380
        # http://teampasswordmanager.com/docs/api-passwords/#update_security_password
381
        log.info('Update security of password %s with %s' % (ID, data))
382
        self.put('passwords/%s/security.json' % ID, data)
383
384
    def update_custom_fields_of_password(self, ID, data):
385
        """Update custom fields definitions of a password."""
386
        # http://teampasswordmanager.com/docs/api-passwords/#update_cf_password
387
        log.info('Update custom fields of password %s with %s' % (ID, data))
388
        self.put('passwords/%s/custom_fields.json' % ID, data)
389
390
    def delete_password(self, ID):
391
        """Delete a password."""
392
        # http://teampasswordmanager.com/docs/api-passwords/#delete_password
393
        log.info('Delete password %s' % ID)
394
        self.delete('passwords/%s.json' % ID)
395
396
    def lock_password(self, ID):
397
        """Lock a password."""
398
        # http://teampasswordmanager.com/docs/api-passwords/#lock_password
399
        log.info('Lock password %s' % ID)
400
        self.put('passwords/%s/lock.json' % ID)
401
402
    def unlock_password(self, ID, reason):
403
        """Unlock a password."""
404
        # http://teampasswordmanager.com/docs/api-passwords/#unlock_password
405
        log.info('Unlock password %s, Reason: %s' % (ID, reason))
406
        self.unlock_reason = reason
407
        self.put('passwords/%s/unlock.json' % ID)
408
409
    def list_mypasswords(self):
410
        """List my passwords."""
411
        # http://teampasswordmanager.com/docs/api-my-passwords/#list_passwords
412
        log.debug('List MyPasswords')
413
        return self.collection('my_passwords.json')
414
415
    def list_mypasswords_search(self, searchstring):
416
        """List my passwords with searchstring."""
417
        # http://teampasswordmanager.com/docs/api-my-passwords/#list_passwords
418
        log.debug('List MyPasswords with %s' % searchstring)
419
        return self.collection('my_passwords/search/%s.json' %
420
                               quote_plus(searchstring))
421
422
    def show_mypassword(self, ID):
423
        """Show my password."""
424
        # http://teampasswordmanager.com/docs/api-my-passwords/#show_password
425
        log.debug('Show MyPassword %s' % ID)
426
        return self.get('my_passwords/%s.json' % ID)
427
428
    def create_mypassword(self, data):
429
        """Create my password."""
430
        # http://teampasswordmanager.com/docs/api-my-passwords/#create_password
431
        log.info('Create MyPassword with %s' % data)
432
        NewID = self.post('my_passwords.json', data).get('id')
433
        log.info('MyPassword has been created with %s' % NewID)
434
        return NewID
435
436
    def update_mypassword(self, ID, data):
437
        """Update my password."""
438
        # http://teampasswordmanager.com/docs/api-my-passwords/#update_password
439
        log.info('Update MyPassword %s with %s' % (ID, data))
440
        self.put('my_passwords/%s.json' % ID, data)
441
442
    def delete_mypassword(self, ID):
443
        """Delete my password."""
444
        # http://teampasswordmanager.com/docs/api-my-passwords/#delete_password
445
        log.info('Delete password %s' % ID)
446
        self.delete('my_passwords/%s.json' % ID)
447
448
    def set_favorite_password(self, ID):
449
        """Set a password as favorite."""
450
        # http://teampasswordmanager.com/docs/api-favorites/#set_fav
451
        log.info('Set password %s as favorite' % ID)
452
        self.post('favorite_passwords/%s.json' % ID)
453
454
    def unset_favorite_password(self, ID):
455
        """Unet a password as favorite."""
456
        # http://teampasswordmanager.com/docs/api-favorites/#del_fav
457
        log.info('Unset password %s as favorite' % ID)
458
        self.delete('favorite_passwords/%s.json' % ID)
459
460
    def set_favorite_project(self, ID):
461
        """Set a project as favorite."""
462
        # http://teampasswordmanager.com/docs/api-favorites/#set_fav
463
        log.info('Set project %s as favorite' % ID)
464
        self.post('favorite_project/%s.json' % ID)
465
466
    def unset_favorite_project(self, ID):
467
        """Unet a project as favorite."""
468
        # http://teampasswordmanager.com/docs/api-favorites/#del_fav
469
        log.info('Unset project %s as favorite' % ID)
470
        self.delete('favorite_project/%s.json' % ID)
471
472
    def list_users(self):
473
        """List users."""
474
        # http://teampasswordmanager.com/docs/api-users/#list_users
475
        log.debug('List users')
476
        return self.collection('users.json')
477
478
    def show_user(self, ID):
479
        """Show a user."""
480
        # http://teampasswordmanager.com/docs/api-users/#show_user
481
        log.debug('Show user %s' % ID)
482
        return self.get('users/%s.json' % ID)
483
484
    def show_me(self):
485
        """Show me."""
486
        # http://teampasswordmanager.com/docs/api-users/#show_me
487
        log.debug('Show Info about own user')
488
        return self.get('users/me.json')
489
490
    def who_am_i(self):
491
        """Who am I."""
492
        return self.show_me()
493
494
    def create_user(self, data):
495
        """Create a User."""
496
        # http://teampasswordmanager.com/docs/api-users/#create_user
497
        log.info('Create user with %s' % data)
498
        NewID = self.post('users.json', data).get('id')
499
        log.info('User has been created with ID %s' % NewID)
500
        return NewID
501
502
    def update_user(self, ID, data):
503
        """Update a User."""
504
        # http://teampasswordmanager.com/docs/api-users/#update_user
505
        log.info('Update user %s with %s' % (ID, data))
506
        self.put('users/%s.json' % ID, data)
507
508
    def change_user_password(self, ID, data):
509
        """Change password of a User."""
510
        # http://teampasswordmanager.com/docs/api-users/#change_password
511
        log.info('Change user %s password' % ID)
512
        self.put('users/%s/change_password.json' % ID, data)
513
514
    def activate_user(self, ID):
515
        """Activate a User."""
516
        # http://teampasswordmanager.com/docs/api-users/#activate_deactivate
517
        log.info('Activate user %s' % ID)
518
        self.put('users/%s/activate.json' % ID)
519
520
    def deactivate_user(self, ID):
521
        """Dectivate a User."""
522
        # http://teampasswordmanager.com/docs/api-users/#activate_deactivate
523
        log.info('Deactivate user %s' % ID)
524
        self.put('users/%s/deactivate.json' % ID)
525
526
    def convert_user_to_ldap(self, ID, DN):
527
        """Convert a normal user to a LDAP user."""
528
        # http://teampasswordmanager.com/docs/api-users/#convert_to_ldap
529
        data = {'login_dn': DN}
530
        log.info('Convert User %s to LDAP DN %s' % (ID, DN))
531
        self.put('users/%s/convert_to_ldap.json' % ID, data)
532
533
    def convert_ldap_user_to_normal(self, ID):
534
        """Convert a LDAP user to a normal user."""
535
        log.info('Convert User %s from LDAP to normal user' % ID)
536
        self.put('users/%s/convert_to_normal.json' % ID)
537
538
    def delete_user(self, ID):
539
        """Delete a user."""
540
        # http://teampasswordmanager.com/docs/api-users/#delete_user
541
        log.info('Delete user %s' % ID)
542
        self.delete('users/%s.json' % ID)
543
544
    def list_groups(self):
545
        """List Groups."""
546
        # http://teampasswordmanager.com/docs/api-groups/#list_groups
547
        log.debug('List groups')
548
        return self.collection('groups.json')
549
550
    def show_group(self, ID):
551
        """Show a Group."""
552
        # http://teampasswordmanager.com/docs/api-groups/#show_group
553
        log.debug('Show group %s' % ID)
554
        return self.get('groups/%s.json' % ID)
555
556
    def create_group(self, data):
557
        """Create a Group."""
558
        # http://teampasswordmanager.com/docs/api-groups/#create_group
559
        log.info('Create group with %s' % data)
560
        NewID = self.post('groups.json', data).get('id')
561
        log.info('Group has been created with ID %s' % NewID)
562
        return NewID
563
564
    def update_group(self, ID, data):
565
        """Update a Group."""
566
        # http://teampasswordmanager.com/docs/api-groups/#update_group
567
        log.info('Update group %s with %s' % (ID, data))
568
        self.put('groups/%s.json' % ID, data)
569
570
    def add_user_to_group(self, GroupID, UserID):
571
        """Add a user to a group."""
572
        # http://teampasswordmanager.com/docs/api-groups/#add_user
573
        log.info('Add User %s to Group %s' % (UserID, GroupID))
574
        self.put('groups/%s/add_user/%s.json' % (GroupID, UserID))
575
576
    def delete_user_from_group(self, GroupID, UserID):
577
        """Delete a user from a group."""
578
        # http://teampasswordmanager.com/docs/api-groups/#del_user
579
        log.info('Delete user %s from group %s' % (UserID, GroupID))
580
        self.put('groups/%s/delete_user/%s.json' % (GroupID, UserID))
581
582
    def delete_group(self, ID):
583
        """Delete a group."""
584
        # http://teampasswordmanager.com/docs/api-groups/#delete_group
585
        log.info('Delete group %s' % ID)
586
        self.delete('groups/%s.json' % ID)
587
588
    def generate_password(self):
589
        """Generate a new random password."""
590
        # http://teampasswordmanager.com/docs/api-passwords-generator/
591
        log.debug('Generate new password')
592
        return self.get('generate_password.json')
593
594
    def get_version(self):
595
        """Get Version Information."""
596
        # http://teampasswordmanager.com/docs/api-version/
597
        log.debug('Get version information')
598
        return self.get('version.json')
599
600
    def get_latest_version(self):
601
        """Check for latest version."""
602
        # http://teampasswordmanager.com/docs/api-version/
603
        log.debug('Get latest version')
604
        return self.get('version/check_latest.json')
605
606
    def up_to_date(self):
607
        """Check if Team Password Manager is up to date."""
608
        VersionInfo = self.get_latest_version()
609
        CurrentVersion = VersionInfo.get('version')
610
        LatestVersion = VersionInfo.get('latest_version')
611
        if  CurrentVersion == LatestVersion:
612
            log.info('TeamPasswordManager is up-to-date!')
613
            log.debug('Current Version: {} Latest Version: {}'.format(LatestVersion, LatestVersion))
614
            return True
615
        else:
616
            log.warning('TeamPasswordManager is not up-to-date!')
617
            log.debug('Current Version: {} Latest Version: {}'.format(LatestVersion, LatestVersion))
618
            return False
619
620
621
class TpmApiv3(TpmApi):
622
    """API v3 based class."""
623
    def __init__(self, url, **kwargs):
624
        super(TpmApiv3, self).__init__('v3', url, kwargs)
625
    """From now on, Functions that only work with API v3."""
626
627
628
class TpmApiv4(TpmApi):
629
    """API v4 based class."""
630
    def __init__(self, url, **kwargs):
631
        super(TpmApiv4, self).__init__('v4', url, kwargs)
632
    """From now on, Functions that only work with API v4."""
633
634
    def list_subprojects(self, ID):
635
        """List subprojects."""
636
        # http://teampasswordmanager.com/docs/api-projects/#list_subprojects
637
        return self.collection('projects/%s/subprojects.json' % ID)
638
639
    def list_subprojects_action(self, ID, action):
640
        """List subprojects with allowed action."""
641
        return self.collection('projects/%s/subprojects/%s.json' %
642
                               (ID, action))
643