Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

store.py 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import errno
  2. import json
  3. import shutil
  4. import subprocess
  5. import warnings
  6. from . import constants
  7. from . import errors
  8. from .utils import create_environment_dict
  9. class Store:
  10. def __init__(self, program, environment=None):
  11. """ Create a store object that acts as an interface to
  12. perform the basic operations for storing, retrieving
  13. and erasing credentials using `program`.
  14. """
  15. self.program = constants.PROGRAM_PREFIX + program
  16. self.exe = shutil.which(self.program)
  17. self.environment = environment
  18. if self.exe is None:
  19. warnings.warn(
  20. '{} not installed or not available in PATH'.format(
  21. self.program
  22. )
  23. )
  24. def get(self, server):
  25. """ Retrieve credentials for `server`. If no credentials are found,
  26. a `StoreError` will be raised.
  27. """
  28. if not isinstance(server, bytes):
  29. server = server.encode('utf-8')
  30. data = self._execute('get', server)
  31. result = json.loads(data.decode('utf-8'))
  32. # docker-credential-pass will return an object for inexistent servers
  33. # whereas other helpers will exit with returncode != 0. For
  34. # consistency, if no significant data is returned,
  35. # raise CredentialsNotFound
  36. if result['Username'] == '' and result['Secret'] == '':
  37. raise errors.CredentialsNotFound(
  38. f'No matching credentials in {self.program}'
  39. )
  40. return result
  41. def store(self, server, username, secret):
  42. """ Store credentials for `server`. Raises a `StoreError` if an error
  43. occurs.
  44. """
  45. data_input = json.dumps({
  46. 'ServerURL': server,
  47. 'Username': username,
  48. 'Secret': secret
  49. }).encode('utf-8')
  50. return self._execute('store', data_input)
  51. def erase(self, server):
  52. """ Erase credentials for `server`. Raises a `StoreError` if an error
  53. occurs.
  54. """
  55. if not isinstance(server, bytes):
  56. server = server.encode('utf-8')
  57. self._execute('erase', server)
  58. def list(self):
  59. """ List stored credentials. Requires v0.4.0+ of the helper.
  60. """
  61. data = self._execute('list', None)
  62. return json.loads(data.decode('utf-8'))
  63. def _execute(self, subcmd, data_input):
  64. if self.exe is None:
  65. raise errors.StoreError(
  66. '{} not installed or not available in PATH'.format(
  67. self.program
  68. )
  69. )
  70. output = None
  71. env = create_environment_dict(self.environment)
  72. try:
  73. output = subprocess.check_output(
  74. [self.exe, subcmd], input=data_input, env=env,
  75. )
  76. except subprocess.CalledProcessError as e:
  77. raise errors.process_store_error(e, self.program)
  78. except OSError as e:
  79. if e.errno == errno.ENOENT:
  80. raise errors.StoreError(
  81. '{} not installed or not available in PATH'.format(
  82. self.program
  83. )
  84. )
  85. else:
  86. raise errors.StoreError(
  87. 'Unexpected OS error "{}", errno={}'.format(
  88. e.strerror, e.errno
  89. )
  90. )
  91. return output