Merge keys when updating an exisiting key
[keymanager.git] / src / leap / keymanager / validation.py
1 # -*- coding: utf-8 -*-
2 # __init__.py
3 # Copyright (C) 2014 LEAP
4 #
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 """
19 Validation levels implementation for key managment.
20
21 See:
22     https://lists.riseup.net/www/arc/leap-discuss/2014-09/msg00000.html
23 """
24
25
26 from datetime import datetime
27 from enum import Enum
28
29
30 ValidationLevel = Enum(
31     "Weak_Chain",
32     "Provider_Trust",
33     "Provider_Endorsement",
34     "Third_Party_Endorsement",
35     "Third_Party_Consensus",
36     "Historically_Auditing",
37     "Known_Key",
38     "Fingerprint")
39
40
41 def toValidationLevel(value):
42     """
43     Convert a string representation of a validation level into
44     C{ValidationLevel}
45
46     :param value: validation level
47     :type value: str
48     :rtype: ValidationLevel
49     :raises ValueError: if C{value} is not a validation level
50     """
51     for level in ValidationLevel:
52         if value == str(level):
53             return level
54     raise ValueError("Not valid validation level: %s" % (value,))
55
56
57 def can_upgrade(new_key, old_key):
58     """
59     :type new_key: EncryptionKey
60     :type old_key: EncryptionKey
61     :rtype: bool
62     """
63     # XXX not succesfully used and strict high validation level (#6211)
64     # XXX implement key signature checking (#6120)
65
66     # First contact
67     if old_key is None:
68         return True
69
70     if new_key.address != old_key.address:
71         # XXX how do we map multiple IDs? (#6212)
72         return False
73
74     # An update of the same key
75     if new_key.fingerprint == old_key.fingerprint:
76         return True
77
78     # Manually verified fingerprint
79     if new_key.validation == ValidationLevel.Fingerprint:
80         return True
81
82     # Expired key and higher validation level
83     if old_key.expiry_date:
84         old_expiry_date = datetime.fromtimestamp(int(old_key.expiry_date))
85         if (old_expiry_date < datetime.now() and
86                 new_key.validation >= old_key.validation):
87             return True
88
89     # No expiration date and higher validation level
90     elif new_key.validation >= old_key.validation:
91         return True
92
93     return False