1# This file is part of Gajim.
2#
3# Gajim is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published
5# by the Free Software Foundation; version 3 only.
6#
7# Gajim is distributed in the hope that it will be useful,
8# but WITHOUT ANY WARRANTY; without even the implied warranty of
9# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10# GNU General Public License for more details.
11#
12# You should have received a copy of the GNU General Public License
13# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
14
15
16import logging
17
18from gi.repository import GLib
19from gi.repository import Gio
20
21from gajim.common import configpaths
22
23from gajim.common.helpers import get_random_string
24from gajim.common.helpers import write_file_async
25
26
27log = logging.getLogger('gajim.c.cert_store')
28
29
30class CertificateStore:
31    def __init__(self):
32        self._path = configpaths.get('CERT_STORE')
33        self._certs = []
34
35        self._load_certificates()
36
37    def _get_random_path(self):
38        filename = get_random_string()
39        path = self._path / filename
40        if path.exists():
41            return self._get_random_path()
42        return path
43
44    def _load_certificates(self):
45        for path in self._path.iterdir():
46            if path.is_dir():
47                continue
48            try:
49                cert = Gio.TlsCertificate.new_from_file(str(path))
50            except GLib.Error as error:
51                log.warning('Can\'t load certificate: %s, %s', path, error)
52                continue
53
54            log.info('Loaded: %s', path.stem)
55            self._certs.append(cert)
56
57        log.info('%s Certificates loaded', len(self._certs))
58
59    def get_certificates(self):
60        return list(self._certs)
61
62    def add_certificate(self, certificate):
63        log.info('Add certificate to trust store')
64        self._certs.append(certificate)
65        pem = certificate.props.certificate_pem
66        path = self._get_random_path()
67        write_file_async(path,
68                         pem.encode(),
69                         self._on_certificate_write_finished,
70                         path)
71
72    def verify(self, certificate, tls_errors):
73        if Gio.TlsCertificateFlags.UNKNOWN_CA in tls_errors:
74            for trusted_certificate in self._certs:
75                if trusted_certificate.is_same(certificate):
76                    tls_errors.remove(Gio.TlsCertificateFlags.UNKNOWN_CA)
77                    break
78
79        if not tls_errors:
80            return True
81        return False
82
83    @staticmethod
84    def _on_certificate_write_finished(data, error, path):
85        if data is None:
86            log.error('Can\'t store certificate: %s', error)
87            return
88
89        log.info('Certificate stored: %s', path)
90