forms.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. from __future__ import unicode_literals
  2. from Crypto.Cipher import PKCS1_OAEP
  3. from Crypto.PublicKey import RSA
  4. from django import forms
  5. from django.db.models import Count
  6. from dcim.models import Device
  7. from utilities.forms import BootstrapMixin, BulkEditForm, CSVDataField, FilterChoiceField, SlugField
  8. from .models import Secret, SecretRole, UserKey
  9. def validate_rsa_key(key, is_secret=True):
  10. """
  11. Validate the format and type of an RSA key.
  12. """
  13. try:
  14. key = RSA.importKey(key)
  15. except ValueError:
  16. raise forms.ValidationError("Invalid RSA key. Please ensure that your key is in PEM (base64) format.")
  17. except Exception as e:
  18. raise forms.ValidationError("Invalid key detected: {}".format(e))
  19. if is_secret and not key.has_private():
  20. raise forms.ValidationError("This looks like a public key. Please provide your private RSA key.")
  21. elif not is_secret and key.has_private():
  22. raise forms.ValidationError("This looks like a private key. Please provide your public RSA key.")
  23. try:
  24. PKCS1_OAEP.new(key)
  25. except:
  26. raise forms.ValidationError("Error validating RSA key. Please ensure that your key supports PKCS#1 OAEP.")
  27. #
  28. # Secret roles
  29. #
  30. class SecretRoleForm(BootstrapMixin, forms.ModelForm):
  31. slug = SlugField()
  32. class Meta:
  33. model = SecretRole
  34. fields = ['name', 'slug']
  35. #
  36. # Secrets
  37. #
  38. class SecretForm(BootstrapMixin, forms.ModelForm):
  39. plaintext = forms.CharField(max_length=65535, required=False, label='Plaintext',
  40. widget=forms.PasswordInput(attrs={'class': 'requires-session-key'}))
  41. plaintext2 = forms.CharField(max_length=65535, required=False, label='Plaintext (verify)',
  42. widget=forms.PasswordInput())
  43. class Meta:
  44. model = Secret
  45. fields = ['role', 'name', 'plaintext', 'plaintext2']
  46. def clean(self):
  47. if self.cleaned_data['plaintext'] != self.cleaned_data['plaintext2']:
  48. raise forms.ValidationError({
  49. 'plaintext2': "The two given plaintext values do not match. Please check your input."
  50. })
  51. class SecretCSVForm(forms.ModelForm):
  52. device = forms.ModelChoiceField(
  53. queryset=Device.objects.all(),
  54. to_field_name='name',
  55. help_text='Device name',
  56. error_messages={
  57. 'invalid_choice': 'Device not found.',
  58. }
  59. )
  60. role = forms.ModelChoiceField(
  61. queryset=SecretRole.objects.all(),
  62. to_field_name='name',
  63. help_text='Name of assigned role',
  64. error_messages={
  65. 'invalid_choice': 'Invalid secret role.',
  66. }
  67. )
  68. plaintext = forms.CharField(
  69. help_text='Plaintext secret data'
  70. )
  71. class Meta:
  72. model = Secret
  73. fields = ['device', 'role', 'name', 'plaintext']
  74. def save(self, *args, **kwargs):
  75. s = super(SecretCSVForm, self).save(*args, **kwargs)
  76. s.plaintext = str(self.cleaned_data['plaintext'])
  77. return s
  78. class SecretBulkEditForm(BootstrapMixin, BulkEditForm):
  79. pk = forms.ModelMultipleChoiceField(queryset=Secret.objects.all(), widget=forms.MultipleHiddenInput)
  80. role = forms.ModelChoiceField(queryset=SecretRole.objects.all(), required=False)
  81. name = forms.CharField(max_length=100, required=False)
  82. class Meta:
  83. nullable_fields = ['name']
  84. class SecretFilterForm(BootstrapMixin, forms.Form):
  85. q = forms.CharField(required=False, label='Search')
  86. role = FilterChoiceField(
  87. queryset=SecretRole.objects.annotate(filter_count=Count('secrets')),
  88. to_field_name='slug'
  89. )
  90. #
  91. # UserKeys
  92. #
  93. class UserKeyForm(BootstrapMixin, forms.ModelForm):
  94. class Meta:
  95. model = UserKey
  96. fields = ['public_key']
  97. help_texts = {
  98. 'public_key': "Enter your public RSA key. Keep the private one with you; you'll need it for decryption.",
  99. }
  100. def clean_public_key(self):
  101. key = self.cleaned_data['public_key']
  102. # Validate the RSA key format.
  103. validate_rsa_key(key, is_secret=False)
  104. return key
  105. class ActivateUserKeyForm(forms.Form):
  106. _selected_action = forms.ModelMultipleChoiceField(queryset=UserKey.objects.all(), label='User Keys')
  107. secret_key = forms.CharField(label='Your private key', widget=forms.Textarea(attrs={'class': 'vLargeTextField'}))