CryptoDataHub 0.12.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. CryptoDataHub-0.12.6.dist-info/LICENSE.txt +373 -0
  2. CryptoDataHub-0.12.6.dist-info/METADATA +119 -0
  3. CryptoDataHub-0.12.6.dist-info/RECORD +70 -0
  4. CryptoDataHub-0.12.6.dist-info/WHEEL +5 -0
  5. CryptoDataHub-0.12.6.dist-info/top_level.txt +1 -0
  6. cryptodatahub/__init__.py +0 -0
  7. cryptodatahub/__setup__.py +10 -0
  8. cryptodatahub/common/__init__.py +0 -0
  9. cryptodatahub/common/algorithm.py +164 -0
  10. cryptodatahub/common/attack-named.json +74 -0
  11. cryptodatahub/common/attack-type.json +58 -0
  12. cryptodatahub/common/authentication.json +113 -0
  13. cryptodatahub/common/block-cipher-mode.json +75 -0
  14. cryptodatahub/common/block-cipher.json +474 -0
  15. cryptodatahub/common/certificate-transparency-log.json +2394 -0
  16. cryptodatahub/common/client.json +20 -0
  17. cryptodatahub/common/dhparam-well-known.json +1975 -0
  18. cryptodatahub/common/ecparam-well-known.json +1868 -0
  19. cryptodatahub/common/entity.json +269 -0
  20. cryptodatahub/common/entity.py +110 -0
  21. cryptodatahub/common/exception.py +28 -0
  22. cryptodatahub/common/grade.py +200 -0
  23. cryptodatahub/common/hash.json +273 -0
  24. cryptodatahub/common/key-exchange.json +140 -0
  25. cryptodatahub/common/key.py +571 -0
  26. cryptodatahub/common/mac.json +404 -0
  27. cryptodatahub/common/named-group.json +902 -0
  28. cryptodatahub/common/parameter.py +149 -0
  29. cryptodatahub/common/root-certificate.json +19240 -0
  30. cryptodatahub/common/server.json +56 -0
  31. cryptodatahub/common/signature.json +233 -0
  32. cryptodatahub/common/standard.json +57 -0
  33. cryptodatahub/common/stores.py +323 -0
  34. cryptodatahub/common/types.py +524 -0
  35. cryptodatahub/common/utils.py +112 -0
  36. cryptodatahub/common/vulnerability.json +2 -0
  37. cryptodatahub/dnsrec/__init__.py +0 -0
  38. cryptodatahub/dnsrec/algorithm.json +114 -0
  39. cryptodatahub/dnsrec/algorithm.py +87 -0
  40. cryptodatahub/dnsrec/digest-type.json +26 -0
  41. cryptodatahub/dnsrec/rr-type.json +805 -0
  42. cryptodatahub/ssh/__init__.py +0 -0
  43. cryptodatahub/ssh/algorithm.py +194 -0
  44. cryptodatahub/ssh/compression-algorithm.json +24 -0
  45. cryptodatahub/ssh/elliptic-curve-identifier.json +50 -0
  46. cryptodatahub/ssh/encryption-algorithm.json +587 -0
  47. cryptodatahub/ssh/host-key-algorithm.json +482 -0
  48. cryptodatahub/ssh/kex-algorithm.json +709 -0
  49. cryptodatahub/ssh/mac-algorithm.json +566 -0
  50. cryptodatahub/tls/__init__.py +0 -0
  51. cryptodatahub/tls/algorithm.py +324 -0
  52. cryptodatahub/tls/certificate-compression-algorithm.json +14 -0
  53. cryptodatahub/tls/cipher-kind.json +171 -0
  54. cryptodatahub/tls/cipher-suite-extension.json +10 -0
  55. cryptodatahub/tls/cipher-suite.json +5098 -0
  56. cryptodatahub/tls/client.json +4757 -0
  57. cryptodatahub/tls/client.py +220 -0
  58. cryptodatahub/tls/compression-method.json +20 -0
  59. cryptodatahub/tls/ec-point-format.json +20 -0
  60. cryptodatahub/tls/extension-type.json +282 -0
  61. cryptodatahub/tls/grease-one-byte.json +34 -0
  62. cryptodatahub/tls/grease-two-byte.json +66 -0
  63. cryptodatahub/tls/hash-and-signature-algorithm.json +266 -0
  64. cryptodatahub/tls/named-curve.json +292 -0
  65. cryptodatahub/tls/next-protocol-name.json +20 -0
  66. cryptodatahub/tls/protocol-name.json +71 -0
  67. cryptodatahub/tls/psk-key-exchange-mode.json +10 -0
  68. cryptodatahub/tls/token-binding-paramater.json +14 -0
  69. cryptodatahub/tls/version.json +154 -0
  70. cryptodatahub/tls/version.py +17 -0
@@ -0,0 +1,269 @@
1
+ {
2
+ "AKAMAI": {
3
+ "name": "ANSI",
4
+ "long_name": "American National Standards Institute",
5
+ "type": "NONPROFIT_ORG",
6
+ "activities": [
7
+ "STANDARD_DEVELOPER"
8
+ ]
9
+ },
10
+ "ANSI": {
11
+ "name": "Akamai Technologies",
12
+ "long_name": "Akamai Technologies, Inc.",
13
+ "type": "FOR_PROFIT_ORG",
14
+ "activities": [
15
+ "CT_LOG_OPERATOR"
16
+ ]
17
+ },
18
+ "APPLE": {
19
+ "name": "Apple",
20
+ "long_name": "Apple Inc.",
21
+ "type": "FOR_PROFIT_ORG",
22
+ "activities": [
23
+ "CA_TRUST_STORE_OWNER"
24
+ ]
25
+ },
26
+ "ASF": {
27
+ "name": "Apache Software Foundation",
28
+ "long_name": null,
29
+ "type": "NOT_FOR_PROFIT_ORG",
30
+ "activities": [
31
+ "SERVER_DEVELOPER"
32
+ ]
33
+ },
34
+ "BEIJING_PUCHUANGSIDA_TECHNOLOGY_LTD": {
35
+ "name": "Beijing PuChuangSiDa Technology Ltd.",
36
+ "long_name": null,
37
+ "type": "FOR_PROFIT_ORG",
38
+ "activities": [
39
+ "CT_LOG_OPERATOR"
40
+ ]
41
+ },
42
+ "CERTICOM": {
43
+ "name": "Certicom",
44
+ "long_name": "Certicom Corp.",
45
+ "type": "FOR_PROFIT_ORG",
46
+ "activities": [
47
+ "STANDARD_DEVELOPER"
48
+ ]
49
+ },
50
+ "CERTLY": {
51
+ "name": "Certly",
52
+ "long_name": "Certly VOF",
53
+ "type": "FOR_PROFIT_ORG",
54
+ "activities": [
55
+ "CT_LOG_OPERATOR"
56
+ ]
57
+ },
58
+ "CLOUDFLARE": {
59
+ "name": "Cloudflare",
60
+ "long_name": "Cloudflare, Inc.",
61
+ "type": "FOR_PROFIT_ORG",
62
+ "activities": [
63
+ "CT_LOG_OPERATOR"
64
+ ]
65
+ },
66
+ "CNNIC": {
67
+ "name": "CNNIC",
68
+ "long_name": "China Internet Network Information Center",
69
+ "type": "GOV_ORG",
70
+ "activities": [
71
+ "CT_LOG_OPERATOR"
72
+ ]
73
+ },
74
+ "DIGICERT": {
75
+ "name": "DigiCert",
76
+ "long_name": "DigiCert, Inc.",
77
+ "type": "FOR_PROFIT_ORG",
78
+ "activities": [
79
+ "CT_LOG_OPERATOR"
80
+ ]
81
+ },
82
+ "F5": {
83
+ "name": "F5",
84
+ "long_name": "F5, Inc.",
85
+ "type": "FOR_PROFIT_ORG",
86
+ "activities": [
87
+ "SERVER_DEVELOPER"
88
+ ]
89
+ },
90
+ "GDCA": {
91
+ "name": "Guangdong CA",
92
+ "long_name": "Digital Security Times Technology Co., Ltd.",
93
+ "type": "FOR_PROFIT_ORG",
94
+ "activities": [
95
+ "CT_LOG_OPERATOR"
96
+ ]
97
+ },
98
+ "GOOGLE": {
99
+ "name": "Google",
100
+ "long_name": "Google LLC",
101
+ "type": "FOR_PROFIT_ORG",
102
+ "activities": [
103
+ "CA_TRUST_STORE_OWNER",
104
+ "CT_LOG_OPERATOR",
105
+ "CLIENT_DEVELOPER"
106
+ ]
107
+ },
108
+ "IETF": {
109
+ "name": "IETF",
110
+ "long_name": "Internet Engineering Task Force",
111
+ "type": "NONPROFIT_ORG",
112
+ "activities": [
113
+ "STANDARD_DEVELOPER"
114
+ ]
115
+ },
116
+ "IZENPE": {
117
+ "name": "Izenpe SA",
118
+ "long_name": null,
119
+ "type": "FOR_PROFIT_ORG",
120
+ "activities": [
121
+ "CT_LOG_OPERATOR"
122
+ ]
123
+ },
124
+ "LETS_ENCRYPT": {
125
+ "name": "Let's Encrypt",
126
+ "long_name": null,
127
+ "type": "NONPROFIT_ORG",
128
+ "activities": [
129
+ "CT_LOG_OPERATOR"
130
+ ]
131
+ },
132
+ "MATT_PALMER": {
133
+ "name": "Matt Palmer",
134
+ "long_name": null,
135
+ "type": "PRIV_PERSON",
136
+ "activities": [
137
+ "CT_LOG_OPERATOR"
138
+ ]
139
+ },
140
+ "MICROSOFT": {
141
+ "name": "Microsoft",
142
+ "long_name": "Microsoft Corporation",
143
+ "type": "FOR_PROFIT_ORG",
144
+ "activities": [
145
+ "CA_TRUST_STORE_OWNER"
146
+ ]
147
+ },
148
+ "MOZILLA": {
149
+ "name": "Mozilla",
150
+ "long_name": "Mozilla Foundation",
151
+ "type": "NONPROFIT_ORG",
152
+ "activities": [
153
+ "CA_TRUST_STORE_OWNER",
154
+ "CLIENT_DEVELOPER"
155
+ ]
156
+ },
157
+ "NIST": {
158
+ "name": "NIST",
159
+ "long_name": "National Institute of Standards and Technology",
160
+ "type": "NOT_FOR_PROFIT_ORG",
161
+ "activities": [
162
+ "STANDARD_DEVELOPER"
163
+ ]
164
+ },
165
+ "NORDUNET": {
166
+ "name": "NORDUnet",
167
+ "long_name": "Arctic Gateway for Research & Education",
168
+ "type": "NOT_FOR_PROFIT_ORG",
169
+ "activities": [
170
+ "CT_LOG_OPERATOR"
171
+ ]
172
+ },
173
+ "OPERA": {
174
+ "name": "Opera",
175
+ "long_name": "Opera, Ltd.",
176
+ "type": "FOR_PROFIT_ORG",
177
+ "activities": [
178
+ "CLIENT_DEVELOPER"
179
+ ]
180
+ },
181
+ "QIHOO_360": {
182
+ "name": "Qihoo 360",
183
+ "long_name": "360 Security Technology Inc.",
184
+ "type": "FOR_PROFIT_ORG",
185
+ "activities": [
186
+ "CT_LOG_OPERATOR"
187
+ ]
188
+ },
189
+ "SECTIGO": {
190
+ "name": "Sectigo",
191
+ "long_name": null,
192
+ "type": "FOR_PROFIT_ORG",
193
+ "activities": [
194
+ "CT_LOG_OPERATOR"
195
+ ]
196
+ },
197
+ "SHECA": {
198
+ "name": "Shanghai CA",
199
+ "long_name": "Shanghai Digital Certificate Certification Center Co., Ltd.",
200
+ "type": "FOR_PROFIT_ORG",
201
+ "activities": [
202
+ "CT_LOG_OPERATOR"
203
+ ]
204
+ },
205
+ "STARTCOM": {
206
+ "name": "StartCom",
207
+ "long_name": "StartCom Ltd.",
208
+ "type": "FOR_PROFIT_ORG",
209
+ "activities": [
210
+ "CT_LOG_OPERATOR"
211
+ ]
212
+ },
213
+ "TRUSTASIA": {
214
+ "name": "TrustAsia",
215
+ "long_name": "TrustAsia Technologies, Inc.",
216
+ "type": "FOR_PROFIT_ORG",
217
+ "activities": [
218
+ "CT_LOG_OPERATOR"
219
+ ]
220
+ },
221
+ "UP_IN_THE_AIR_CONSULTING": {
222
+ "name": "Up In The Air Consulting",
223
+ "long_name": null,
224
+ "type": "FOR_PROFIT_ORG",
225
+ "activities": [
226
+ "CT_LOG_OPERATOR"
227
+ ]
228
+ },
229
+ "VENAFI": {
230
+ "name": "Venafi",
231
+ "long_name": "Venafi, Inc.",
232
+ "type": "FOR_PROFIT_ORG",
233
+ "activities": [
234
+ "CT_LOG_OPERATOR"
235
+ ]
236
+ },
237
+ "FILIPPO_VALSORDA": {
238
+ "name": "Filippo Valsorda",
239
+ "long_name": null,
240
+ "type": "PRIV_PERSON",
241
+ "activities": [
242
+ "CT_LOG_OPERATOR"
243
+ ]
244
+ },
245
+ "WAP_FORUM": {
246
+ "name": "WAP Forum",
247
+ "long_name": "Wireless Application Protocol Forum Ltd.",
248
+ "type": "NONPROFIT_ORG",
249
+ "activities": [
250
+ "STANDARD_DEVELOPER"
251
+ ]
252
+ },
253
+ "WIETSE_VENEMA": {
254
+ "name": "Wietse Venema",
255
+ "long_name": "Wietse Zweitze Venema",
256
+ "type": "PRIV_PERSON",
257
+ "activities": [
258
+ "CT_LOG_OPERATOR"
259
+ ]
260
+ },
261
+ "WOSIGN": {
262
+ "name": "WoSign",
263
+ "long_name": null,
264
+ "type": "FOR_PROFIT_ORG",
265
+ "activities": [
266
+ "CT_LOG_OPERATOR"
267
+ ]
268
+ }
269
+ }
@@ -0,0 +1,110 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import enum
4
+
5
+ import attr
6
+
7
+ from cryptodatahub.common.types import CryptoDataEnumBase, CryptoDataParamsNamed, convert_enum, convert_iterable
8
+
9
+
10
+ class EntityType(enum.Enum):
11
+ FOR_PROFIT_ORG = 'for-profit organization'
12
+ GOV_ORG = 'governmental organization'
13
+ NONPROFIT_ORG = 'nonprofit organization'
14
+ NOT_FOR_PROFIT_ORG = 'not-for-profit organization'
15
+ PRIV_PERSON = 'private person'
16
+
17
+
18
+ class EntityRole(enum.Enum):
19
+ CA_TRUST_STORE_OWNER = 'CA trust store owner'
20
+ CLIENT_DEVELOPER = 'client developer'
21
+ CT_LOG_OPERATOR = 'certificate transparency log operator'
22
+ SERVER_DEVELOPER = 'server developer'
23
+ STANDARD_DEVELOPER = 'standard developer'
24
+
25
+
26
+ @attr.s(frozen=True)
27
+ class EntityParams(CryptoDataParamsNamed):
28
+ type = attr.ib(
29
+ converter=convert_enum(EntityType),
30
+ validator=attr.validators.instance_of(EntityType)
31
+ )
32
+ activities = attr.ib(
33
+ converter=convert_iterable(convert_enum(EntityRole)),
34
+ validator=attr.validators.deep_iterable(attr.validators.instance_of(EntityRole))
35
+ )
36
+
37
+
38
+ class EntityBase(CryptoDataEnumBase):
39
+ @classmethod
40
+ def get_items_by_role(cls, role):
41
+ if not hasattr(cls, '_ITEMS_BY_ROLE'):
42
+ items_by_role = {}
43
+
44
+ for activity in EntityRole:
45
+ items_by_role[activity] = []
46
+
47
+ for entity in cls:
48
+ for activity in entity.value.activities:
49
+ items_by_role[activity].append(entity)
50
+
51
+ cls._ITEMS_BY_ROLE = {
52
+ role: tuple(activities)
53
+ for role, activities in items_by_role.items()
54
+ }
55
+
56
+ return cls._ITEMS_BY_ROLE[role]
57
+
58
+
59
+ Entity = EntityBase('Entity', EntityBase.get_json_records(EntityParams))
60
+
61
+
62
+ class ClientType(enum.Enum):
63
+ CT_LOG_OPERATOR = 'certificate transparency log operator'
64
+ WEB_BROWSER = 'web browser'
65
+
66
+
67
+ @attr.s(frozen=True)
68
+ class ClientParams(CryptoDataParamsNamed):
69
+ type = attr.ib(
70
+ converter=convert_enum(ClientType),
71
+ validator=attr.validators.instance_of(ClientType)
72
+ )
73
+ developer = attr.ib(
74
+ converter=convert_enum(Entity),
75
+ validator=attr.validators.instance_of(Entity)
76
+ )
77
+
78
+ def __str__(self):
79
+ return '{} {}'.format(self.developer.value.name, self.name)
80
+
81
+
82
+ Client = CryptoDataEnumBase('Client', CryptoDataEnumBase.get_json_records(ClientParams))
83
+
84
+
85
+ class ServerType(enum.Enum):
86
+ FTP_SERVER = 'ftp server'
87
+ MAIL_SERVER = 'mail server'
88
+ WEB_SERVER = 'web server'
89
+ TCP_SERVER = 'tcp server'
90
+
91
+
92
+ @attr.s(frozen=True)
93
+ class ServerParams(CryptoDataParamsNamed):
94
+ types = attr.ib(
95
+ converter=convert_iterable(convert_enum(ServerType)),
96
+ validator=attr.validators.deep_iterable(attr.validators.instance_of(ServerType))
97
+ )
98
+ developers = attr.ib(
99
+ converter=convert_iterable(convert_enum(Entity)),
100
+ validator=attr.validators.deep_iterable(attr.validators.instance_of(Entity))
101
+ )
102
+
103
+ def __str__(self):
104
+ server_str = self.name
105
+ if self.developers:
106
+ server_str += ' ({})'.format(','.join(map(lambda developer: developer.value.name, self.developers)))
107
+ return server_str
108
+
109
+
110
+ Server = CryptoDataEnumBase('Server', CryptoDataEnumBase.get_json_records(ServerParams))
@@ -0,0 +1,28 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import enum
4
+ import six
5
+
6
+ import attr
7
+
8
+
9
+ @attr.s(init=False)
10
+ class InvalidValue(Exception):
11
+ value = attr.ib()
12
+
13
+ def __init__(self, value, type_class, class_member=None):
14
+ if isinstance(value, enum.IntEnum):
15
+ message = hex(value.value)
16
+ elif isinstance(value, int):
17
+ message = hex(value)
18
+ else:
19
+ message = value
20
+ message = hex(value) if isinstance(value, int) else repr(value)
21
+ type_name = type_class.__name__ if hasattr(type_class, '__name__') else str(type(type_class))
22
+ message = six.ensure_text('{} is not a valid {}').format(message, type_name)
23
+ if class_member is not None:
24
+ message = six.ensure_text('{} {} value').format(message, class_member)
25
+
26
+ super(InvalidValue, self).__init__(message)
27
+
28
+ self.value = value
@@ -0,0 +1,200 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import abc
4
+ import enum
5
+ import functools
6
+
7
+ import six
8
+
9
+ import attr
10
+
11
+ from cryptodatahub.common.types import (
12
+ CryptoDataEnumBase,
13
+ CryptoDataEnumOIDBase,
14
+ CryptoDataParamsNamed,
15
+ convert_enum,
16
+ convert_iterable,
17
+ convert_dict_to_object,
18
+ )
19
+
20
+
21
+ @functools.total_ordering
22
+ @attr.s(frozen=True, order=False, eq=False, hash=True)
23
+ class GradeTypeParams(CryptoDataParamsNamed):
24
+ _numeric = attr.ib(validator=attr.validators.instance_of(six.integer_types))
25
+
26
+ def __eq__(self, other):
27
+ return self._numeric == other._numeric
28
+
29
+ def __lt__(self, other):
30
+ return self._numeric < other._numeric
31
+
32
+
33
+ class Grade(enum.Enum):
34
+ SECURE = GradeTypeParams(
35
+ name='secure',
36
+ long_name=None,
37
+ numeric=0,
38
+ )
39
+ DEPRECATED = GradeTypeParams(
40
+ name='deprecated',
41
+ long_name=None,
42
+ numeric=-1,
43
+ )
44
+ WEAK = GradeTypeParams(
45
+ name='weak',
46
+ long_name=None,
47
+ numeric=-2,
48
+ )
49
+ INSECURE = GradeTypeParams(
50
+ name='insecure',
51
+ long_name=None,
52
+ numeric=-3,
53
+ )
54
+
55
+
56
+ @attr.s(frozen=True)
57
+ class AttackTypeParams(CryptoDataParamsNamed):
58
+ pass
59
+
60
+
61
+ AttackType = CryptoDataEnumOIDBase('AttackType', CryptoDataEnumBase.get_json_records(AttackTypeParams))
62
+
63
+
64
+ @attr.s(frozen=True)
65
+ class AttackNamedParams(CryptoDataParamsNamed):
66
+ grade = attr.ib(
67
+ converter=convert_enum(Grade),
68
+ validator=attr.validators.instance_of(Grade)
69
+ )
70
+ attack_type = attr.ib(
71
+ converter=convert_enum(AttackType),
72
+ validator=attr.validators.optional(attr.validators.instance_of(AttackType))
73
+ )
74
+
75
+
76
+ AttackNamed = CryptoDataEnumOIDBase('AttackNamed', CryptoDataEnumBase.get_json_records(AttackNamedParams))
77
+
78
+
79
+ @attr.s(frozen=True, eq=False)
80
+ class Gradeable(object):
81
+ @staticmethod
82
+ def _get_vulnerbilities(obj):
83
+ if obj is None:
84
+ return [None]
85
+
86
+ if isinstance(obj, Vulnerability):
87
+ return [obj]
88
+
89
+ if isinstance(obj, (list, tuple)):
90
+ result = []
91
+ for gradeable in obj:
92
+ if isinstance(gradeable, GradeableComplex):
93
+ result.append(Gradeable._get_vulnerbilities(gradeable.gradeables))
94
+ elif isinstance(gradeable, GradeableVulnerabilities):
95
+ result.append(gradeable.vulnerabilities)
96
+ else:
97
+ result.append(Gradeable._get_vulnerbilities(gradeable))
98
+
99
+ return result
100
+
101
+ raise NotImplementedError(type(obj))
102
+
103
+ @staticmethod
104
+ def _flatten_vulnerabilities(vulnerabilities):
105
+ if not vulnerabilities:
106
+ return vulnerabilities
107
+
108
+ if isinstance(vulnerabilities[0], list):
109
+ return (
110
+ Gradeable._flatten_vulnerabilities(vulnerabilities[0]) +
111
+ Gradeable._flatten_vulnerabilities(vulnerabilities[1:])
112
+ )
113
+ return vulnerabilities[:1] + Gradeable._flatten_vulnerabilities(vulnerabilities[1:])
114
+
115
+ @staticmethod
116
+ def get_min_grade(vulnerabilities):
117
+ vulnerabilities = Gradeable._flatten_vulnerabilities((Gradeable._get_vulnerbilities(vulnerabilities)))
118
+ if not vulnerabilities:
119
+ return Grade.SECURE
120
+
121
+ grades = set(
122
+ vulnerability.grade
123
+ for vulnerability in vulnerabilities
124
+ if vulnerability is not None
125
+ )
126
+ if grades:
127
+ return min(grades, key=lambda grade: grade.value)
128
+
129
+ return None
130
+
131
+ @property
132
+ @abc.abstractmethod
133
+ def min_grade(self):
134
+ raise NotImplementedError()
135
+
136
+
137
+ @attr.s(frozen=True)
138
+ class Vulnerability(object):
139
+ attack_type = attr.ib(
140
+ converter=convert_enum(AttackType),
141
+ validator=attr.validators.optional(attr.validators.instance_of(AttackType))
142
+ )
143
+ grade = attr.ib(
144
+ converter=convert_enum(Grade),
145
+ validator=attr.validators.instance_of(Grade)
146
+ )
147
+ named = attr.ib(
148
+ converter=convert_enum(AttackNamed),
149
+ validator=attr.validators.optional(attr.validators.instance_of(AttackNamed))
150
+ )
151
+
152
+
153
+ @attr.s(frozen=True, eq=False)
154
+ class GradeableSimple(Gradeable):
155
+ @property
156
+ @abc.abstractmethod
157
+ def grade(self):
158
+ raise NotImplementedError()
159
+
160
+ @abc.abstractmethod
161
+ def __str__(self):
162
+ raise NotImplementedError()
163
+
164
+ @property
165
+ def min_grade(self):
166
+ return self.grade
167
+
168
+
169
+ @attr.s(frozen=True, eq=False)
170
+ class GradeableVulnerabilities(Gradeable):
171
+ vulnerabilities = attr.ib(
172
+ converter=convert_iterable(convert_dict_to_object(Vulnerability)),
173
+ validator=attr.validators.optional(
174
+ validator=attr.validators.deep_iterable(member_validator=attr.validators.instance_of(Vulnerability))
175
+ )
176
+ )
177
+
178
+ @classmethod
179
+ @abc.abstractmethod
180
+ def get_gradeable_name(cls):
181
+ raise NotImplementedError()
182
+
183
+ @property
184
+ def min_grade(self):
185
+ return self.get_min_grade(self.vulnerabilities)
186
+
187
+
188
+ @attr.s(eq=False)
189
+ class GradeableComplex(Gradeable):
190
+ gradeables = attr.ib(
191
+ init=False,
192
+ default=None,
193
+ validator=attr.validators.optional(attr.validators.deep_iterable(
194
+ member_validator=attr.validators.optional(attr.validators.instance_of(Gradeable))
195
+ ))
196
+ )
197
+
198
+ @property
199
+ def min_grade(self):
200
+ return self.get_min_grade(self.gradeables)