Alexandr Lovtsov | 3ad2062 | 2019-02-20 13:08:01 +0300 | [diff] [blame] | 1 | # -*- coding: utf-8 -*- |
| 2 | # _state/aptkey.py |
| 3 | """ |
| 4 | Manage apt keys |
| 5 | """ |
| 6 | from __future__ import absolute_import, print_function, unicode_literals |
| 7 | |
| 8 | from base64 import b64encode, b64decode |
| 9 | from binascii import Error as binasciiError |
| 10 | |
| 11 | def __virtual__(): |
| 12 | """Only load if 'pkg' (aptpkg) module has necessary functions""" |
| 13 | |
| 14 | if not 'pkg.add_repo_key' in __salt__ or not 'pkg.get_repo_keys' in __salt__: |
| 15 | return False, "'pkg.add_repo_key' and 'pkg.get_repo_keys' functions are required" |
| 16 | return True |
| 17 | |
| 18 | def _get_fingerprints(input_text): |
| 19 | """Get fingerprint(s) for given text |
| 20 | |
| 21 | :param str input_text: text to get fingerprint(s) from it |
| 22 | |
| 23 | :return: |
| 24 | A list of found fingerprint(s) |
| 25 | :rtype list: |
| 26 | |
| 27 | """ |
| 28 | fingerprints = [] |
| 29 | cmd = 'apt-key adv --with-fingerprint --with-colons --dry-run -' |
| 30 | out = __salt__['cmd.run_stdout'](cmd, stdin=input_text, python_shell=False) |
| 31 | for line in out.split('\n'): |
| 32 | line = line.split(':') |
| 33 | if line[0] == 'fpr': |
| 34 | fingerprints.append(line[-2]) |
| 35 | return fingerprints |
| 36 | |
| 37 | |
| 38 | def added(name, key_text=None, key_url=None): |
| 39 | """Ensure that given key added to APT's key storage |
| 40 | |
| 41 | :param str name: |
| 42 | Just an ID, it does not used at all. |
| 43 | :param str key_text: |
| 44 | Key to add as a plain text or base64-encoded. |
| 45 | :param str key_url: |
| 46 | URL from which key should be fetched. Supported URLs: salt://, http://, |
| 47 | https:// and file://. |
| 48 | |
| 49 | Examples: |
| 50 | |
| 51 | .. code-block:: yaml |
| 52 | |
| 53 | # Base64 encoded key |
| 54 | {% set repo_key = salt['hashutil.base64_b64encode'](repo.key) %} |
| 55 | linux_repo_ubuntu_key: |
| 56 | aptkey.added: |
| 57 | - key_text: {{ repo_key }} |
| 58 | |
| 59 | .. code-block:: yaml |
| 60 | |
| 61 | # Plaintext key |
| 62 | linux_repo_ubuntu_key: |
| 63 | aptkey.added: |
| 64 | - key_text: '{{ repo.key | replace("\n", "\\n") }}' |
| 65 | |
| 66 | .. code-block:: yaml |
| 67 | |
| 68 | linux_repo_ubuntu_key: |
| 69 | aptkey.added: |
| 70 | - key_url: 'https://example.com/key.asc' |
| 71 | """ |
| 72 | ret = {'name': name, |
| 73 | 'result': None if __opts__['test'] else True, |
| 74 | 'changes': {}, |
| 75 | 'comment': ''} |
| 76 | |
| 77 | if not key_text and not key_url: |
| 78 | ret['result'] = False, |
| 79 | ret['comment'] = 'No key to add provided' |
| 80 | return ret |
| 81 | if key_text and key_url: |
| 82 | ret['result'] = False |
| 83 | ret['comment'] = 'Only one of key_text or key_url is permitted' |
| 84 | return ret |
| 85 | |
| 86 | # If key_url provided fetch it before proceeding |
| 87 | if key_url: |
| 88 | # This only supports salt://, http://, https:// and file:// URLs |
| 89 | key_text = __salt__['cp.get_url'](key_url, dest=None) |
| 90 | |
| 91 | # Try to apply base64 decoding to key_text, just in case... |
| 92 | try: |
| 93 | # Decode key_text if it is base64 encoded string |
| 94 | decoded_key_text = b64decode(key_text) |
| 95 | # the simplest available check that given string was base64 encoded |
| 96 | if b64encode(decoded_key_text) == key_text: |
| 97 | key_text = decoded_key_text |
| 98 | except TypeError, binasciiError: # the first is for py2, the second for py3 |
| 99 | pass |
| 100 | |
| 101 | # Get apt's keys and their fingerprints |
| 102 | apt_keys = __salt__['pkg.get_repo_keys']() |
| 103 | apt_fingerprints = [key.get('fingerprint') for _, key in apt_keys.items()] |
| 104 | |
| 105 | key_fingerprints = _get_fingerprints(key_text) |
| 106 | # If any of given fingerprints does not present in apt keys |
| 107 | # then add all of them |
| 108 | if not set(key_fingerprints).issubset(set(apt_fingerprints)): |
| 109 | if __opts__['test']: |
| 110 | ret['result'] = None |
| 111 | ret['changes'] = {'key': key_text} |
| 112 | return ret |
| 113 | |
| 114 | success = __salt__['pkg.add_repo_key'](text=key_text) |
| 115 | if success: |
| 116 | ret['result'] = True |
| 117 | ret['changes'] = {'key': key_text} |
| 118 | else: |
| 119 | ret['result'] = False |
| 120 | ret['comment'] = 'Key was not added because of errors' |
| 121 | return ret |