blob: 8d12829557e3b72f64804b41eaa456750157d7b3 [file] [log] [blame]
Alexandr Lovtsov3ad20622019-02-20 13:08:01 +03001# -*- coding: utf-8 -*-
2# _state/aptkey.py
3"""
4Manage apt keys
5"""
6from __future__ import absolute_import, print_function, unicode_literals
7
8from base64 import b64encode, b64decode
9from binascii import Error as binasciiError
10
11def __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
18def _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
38def 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