Coverage for vpn/models/crypto.py: 84%
82 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.core.exceptions import ValidationError
2from django.db import models
3from django.utils.translation import gettext_lazy as _
5from netbox.models import PrimaryModel
6from vpn.choices import *
8__all__ = (
9 'IKEPolicy',
10 'IKEProposal',
11 'IPSecPolicy',
12 'IPSecProfile',
13 'IPSecProposal',
14)
17#
18# IKE
19#
21class IKEProposal(PrimaryModel):
22 name = models.CharField(
23 verbose_name=_('name'),
24 max_length=100,
25 unique=True,
26 db_collation="natural_sort"
27 )
28 authentication_method = models.CharField(
29 verbose_name=('authentication method'),
30 choices=AuthenticationMethodChoices
31 )
32 encryption_algorithm = models.CharField(
33 verbose_name=_('encryption algorithm'),
34 choices=EncryptionAlgorithmChoices
35 )
36 authentication_algorithm = models.CharField(
37 verbose_name=_('authentication algorithm'),
38 choices=AuthenticationAlgorithmChoices,
39 blank=True,
40 null=True
41 )
42 group = models.PositiveSmallIntegerField(
43 verbose_name=_('group'),
44 choices=DHGroupChoices,
45 help_text=_('Diffie-Hellman group ID')
46 )
47 sa_lifetime = models.PositiveIntegerField(
48 verbose_name=_('SA lifetime'),
49 blank=True,
50 null=True,
51 help_text=_('Security association lifetime (in seconds)')
52 )
54 clone_fields = (
55 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime',
56 )
58 class Meta:
59 ordering = ('name',)
60 verbose_name = _('IKE proposal')
61 verbose_name_plural = _('IKE proposals')
63 def __str__(self):
64 return self.name
67class IKEPolicy(PrimaryModel):
68 name = models.CharField(
69 verbose_name=_('name'),
70 max_length=100,
71 unique=True,
72 db_collation="natural_sort"
73 )
74 version = models.PositiveSmallIntegerField(
75 verbose_name=_('version'),
76 choices=IKEVersionChoices,
77 default=IKEVersionChoices.VERSION_2
78 )
79 mode = models.CharField(
80 verbose_name=_('mode'),
81 choices=IKEModeChoices,
82 blank=True,
83 null=True
84 )
85 proposals = models.ManyToManyField(
86 to='vpn.IKEProposal',
87 related_name='ike_policies',
88 verbose_name=_('proposals')
89 )
90 preshared_key = models.TextField(
91 verbose_name=_('pre-shared key'),
92 blank=True
93 )
95 clone_fields = (
96 'version', 'mode', 'proposals',
97 )
98 prerequisite_models = (
99 'vpn.IKEProposal',
100 )
102 class Meta:
103 ordering = ('name',)
104 verbose_name = _('IKE policy')
105 verbose_name_plural = _('IKE policies')
107 def __str__(self):
108 return self.name
110 def clean(self):
111 super().clean()
113 # Mode is required
114 if self.version == IKEVersionChoices.VERSION_1 and not self.mode:
115 raise ValidationError(_("Mode is required for selected IKE version"))
117 # Mode cannot be used
118 if self.version == IKEVersionChoices.VERSION_2 and self.mode:
119 raise ValidationError(_("Mode cannot be used for selected IKE version"))
122#
123# IPSec
124#
126class IPSecProposal(PrimaryModel):
127 name = models.CharField(
128 verbose_name=_('name'),
129 max_length=100,
130 unique=True,
131 db_collation="natural_sort"
132 )
133 encryption_algorithm = models.CharField(
134 verbose_name=_('encryption'),
135 choices=EncryptionAlgorithmChoices,
136 blank=True,
137 null=True
138 )
139 authentication_algorithm = models.CharField(
140 verbose_name=_('authentication'),
141 choices=AuthenticationAlgorithmChoices,
142 blank=True,
143 null=True
144 )
145 sa_lifetime_seconds = models.PositiveIntegerField(
146 verbose_name=_('SA lifetime (seconds)'),
147 blank=True,
148 null=True,
149 help_text=_('Security association lifetime (seconds)')
150 )
151 sa_lifetime_data = models.PositiveIntegerField(
152 verbose_name=_('SA lifetime (KB)'),
153 blank=True,
154 null=True,
155 help_text=_('Security association lifetime (in kilobytes)')
156 )
158 clone_fields = (
159 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data',
160 )
162 class Meta:
163 ordering = ('name',)
164 verbose_name = _('IPSec proposal')
165 verbose_name_plural = _('IPSec proposals')
167 def __str__(self):
168 return self.name
170 def clean(self):
171 super().clean()
173 # Encryption and/or authentication algorithm must be defined
174 if not self.encryption_algorithm and not self.authentication_algorithm: 174 ↛ exitline 174 didn't return from function 'clean' because the condition on line 174 was always true
175 raise ValidationError(_("Encryption and/or authentication algorithm must be defined"))
178class IPSecPolicy(PrimaryModel):
179 name = models.CharField(
180 verbose_name=_('name'),
181 max_length=100,
182 unique=True,
183 db_collation="natural_sort"
184 )
185 proposals = models.ManyToManyField(
186 to='vpn.IPSecProposal',
187 related_name='ipsec_policies',
188 verbose_name=_('proposals')
189 )
190 pfs_group = models.PositiveSmallIntegerField(
191 verbose_name=_('PFS group'),
192 choices=DHGroupChoices,
193 blank=True,
194 null=True,
195 help_text=_('Diffie-Hellman group for Perfect Forward Secrecy')
196 )
198 clone_fields = (
199 'proposals', 'pfs_group',
200 )
201 prerequisite_models = (
202 'vpn.IPSecProposal',
203 )
205 class Meta:
206 ordering = ('name',)
207 verbose_name = _('IPSec policy')
208 verbose_name_plural = _('IPSec policies')
210 def __str__(self):
211 return self.name
214class IPSecProfile(PrimaryModel):
215 name = models.CharField(
216 verbose_name=_('name'),
217 max_length=100,
218 unique=True,
219 db_collation="natural_sort"
220 )
221 mode = models.CharField(
222 verbose_name=_('mode'),
223 choices=IPSecModeChoices
224 )
225 ike_policy = models.ForeignKey(
226 to='vpn.IKEPolicy',
227 on_delete=models.PROTECT,
228 related_name='ipsec_profiles'
229 )
230 ipsec_policy = models.ForeignKey(
231 to='vpn.IPSecPolicy',
232 on_delete=models.PROTECT,
233 related_name='ipsec_profiles'
234 )
236 clone_fields = (
237 'mode', 'ike_policy', 'ipsec_policy',
238 )
239 prerequisite_models = (
240 'vpn.IKEPolicy',
241 'vpn.IPSecPolicy',
242 )
244 class Meta:
245 ordering = ('name',)
246 verbose_name = _('IPSec profile')
247 verbose_name_plural = _('IPSec profiles')
249 def __str__(self):
250 return self.name