| # -*- coding: utf-8 -*- |
| # _state/aptkey.py |
| """ |
| Manage apt keys |
| """ |
| from __future__ import absolute_import, print_function, unicode_literals |
| |
| from base64 import b64encode, b64decode |
| from binascii import Error as binasciiError |
| |
| def __virtual__(): |
| """Only load if 'pkg' (aptpkg) module has necessary functions""" |
| |
| if not 'pkg.add_repo_key' in __salt__ or not 'pkg.get_repo_keys' in __salt__: |
| return False, "'pkg.add_repo_key' and 'pkg.get_repo_keys' functions are required" |
| return True |
| |
| def _get_fingerprints(input_text): |
| """Get fingerprint(s) for given text |
| |
| :param str input_text: text to get fingerprint(s) from it |
| |
| :return: |
| A list of found fingerprint(s) |
| :rtype list: |
| |
| """ |
| fingerprints = [] |
| cmd = 'apt-key adv --with-fingerprint --with-colons --dry-run -' |
| out = __salt__['cmd.run_stdout'](cmd, stdin=input_text, python_shell=False) |
| for line in out.split('\n'): |
| line = line.split(':') |
| if line[0] == 'fpr': |
| fingerprints.append(line[-2]) |
| return fingerprints |
| |
| |
| def added(name, key_text=None, key_url=None): |
| """Ensure that given key added to APT's key storage |
| |
| :param str name: |
| Just an ID, it does not used at all. |
| :param str key_text: |
| Key to add as a plain text or base64-encoded. |
| :param str key_url: |
| URL from which key should be fetched. Supported URLs: salt://, http://, |
| https:// and file://. |
| |
| Examples: |
| |
| .. code-block:: yaml |
| |
| # Base64 encoded key |
| {% set repo_key = salt['hashutil.base64_b64encode'](repo.key) %} |
| linux_repo_ubuntu_key: |
| aptkey.added: |
| - key_text: {{ repo_key }} |
| |
| .. code-block:: yaml |
| |
| # Plaintext key |
| linux_repo_ubuntu_key: |
| aptkey.added: |
| - key_text: '{{ repo.key | replace("\n", "\\n") }}' |
| |
| .. code-block:: yaml |
| |
| linux_repo_ubuntu_key: |
| aptkey.added: |
| - key_url: 'https://example.com/key.asc' |
| """ |
| ret = {'name': name, |
| 'result': None if __opts__['test'] else True, |
| 'changes': {}, |
| 'comment': ''} |
| |
| if not key_text and not key_url: |
| ret['result'] = False, |
| ret['comment'] = 'No key to add provided' |
| return ret |
| if key_text and key_url: |
| ret['result'] = False |
| ret['comment'] = 'Only one of key_text or key_url is permitted' |
| return ret |
| |
| # If key_url provided fetch it before proceeding |
| if key_url: |
| # This only supports salt://, http://, https:// and file:// URLs |
| key_text = __salt__['cp.get_url'](key_url, dest=None) |
| |
| # Try to apply base64 decoding to key_text, just in case... |
| try: |
| # Decode key_text if it is base64 encoded string |
| decoded_key_text = b64decode(key_text) |
| # the simplest available check that given string was base64 encoded |
| if b64encode(decoded_key_text) == key_text: |
| key_text = decoded_key_text |
| except TypeError, binasciiError: # the first is for py2, the second for py3 |
| pass |
| |
| # Get apt's keys and their fingerprints |
| apt_keys = __salt__['pkg.get_repo_keys']() |
| apt_fingerprints = [key.get('fingerprint') for _, key in apt_keys.items()] |
| |
| key_fingerprints = _get_fingerprints(key_text) |
| # If any of given fingerprints does not present in apt keys |
| # then add all of them |
| if not set(key_fingerprints).issubset(set(apt_fingerprints)): |
| if __opts__['test']: |
| ret['result'] = None |
| ret['changes'] = {'key': key_text} |
| return ret |
| |
| success = __salt__['pkg.add_repo_key'](text=key_text) |
| if success: |
| ret['result'] = True |
| ret['changes'] = {'key': key_text} |
| else: |
| ret['result'] = False |
| ret['comment'] = 'Key was not added because of errors' |
| return ret |