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

1from django.core.exceptions import ValidationError 

2from django.db import models 

3from django.utils.translation import gettext_lazy as _ 

4 

5from netbox.models import PrimaryModel 

6from vpn.choices import * 

7 

8__all__ = ( 

9 'IKEPolicy', 

10 'IKEProposal', 

11 'IPSecPolicy', 

12 'IPSecProfile', 

13 'IPSecProposal', 

14) 

15 

16 

17# 

18# IKE 

19# 

20 

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 ) 

53 

54 clone_fields = ( 

55 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', 'sa_lifetime', 

56 ) 

57 

58 class Meta: 

59 ordering = ('name',) 

60 verbose_name = _('IKE proposal') 

61 verbose_name_plural = _('IKE proposals') 

62 

63 def __str__(self): 

64 return self.name 

65 

66 

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 ) 

94 

95 clone_fields = ( 

96 'version', 'mode', 'proposals', 

97 ) 

98 prerequisite_models = ( 

99 'vpn.IKEProposal', 

100 ) 

101 

102 class Meta: 

103 ordering = ('name',) 

104 verbose_name = _('IKE policy') 

105 verbose_name_plural = _('IKE policies') 

106 

107 def __str__(self): 

108 return self.name 

109 

110 def clean(self): 

111 super().clean() 

112 

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")) 

116 

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")) 

120 

121 

122# 

123# IPSec 

124# 

125 

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 ) 

157 

158 clone_fields = ( 

159 'encryption_algorithm', 'authentication_algorithm', 'sa_lifetime_seconds', 'sa_lifetime_data', 

160 ) 

161 

162 class Meta: 

163 ordering = ('name',) 

164 verbose_name = _('IPSec proposal') 

165 verbose_name_plural = _('IPSec proposals') 

166 

167 def __str__(self): 

168 return self.name 

169 

170 def clean(self): 

171 super().clean() 

172 

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")) 

176 

177 

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 ) 

197 

198 clone_fields = ( 

199 'proposals', 'pfs_group', 

200 ) 

201 prerequisite_models = ( 

202 'vpn.IPSecProposal', 

203 ) 

204 

205 class Meta: 

206 ordering = ('name',) 

207 verbose_name = _('IPSec policy') 

208 verbose_name_plural = _('IPSec policies') 

209 

210 def __str__(self): 

211 return self.name 

212 

213 

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 ) 

235 

236 clone_fields = ( 

237 'mode', 'ike_policy', 'ipsec_policy', 

238 ) 

239 prerequisite_models = ( 

240 'vpn.IKEPolicy', 

241 'vpn.IPSecPolicy', 

242 ) 

243 

244 class Meta: 

245 ordering = ('name',) 

246 verbose_name = _('IPSec profile') 

247 verbose_name_plural = _('IPSec profiles') 

248 

249 def __str__(self): 

250 return self.name