from __future__ import absolute_import, unicode_literals from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from rest_framework.exceptions import ValidationError from mayan.apps.acls.models import AccessControlList from mayan.apps.django_gpg.models import Key from mayan.apps.django_gpg.permissions import permission_key_sign from mayan.apps.rest_api.relations import MultiKwargHyperlinkedIdentityField from .models import DetachedSignature, EmbeddedSignature class BaseSignatureSerializer(serializers.HyperlinkedModelSerializer): document_version_url = MultiKwargHyperlinkedIdentityField( view_kwargs=( { 'lookup_field': 'document_version_id', 'lookup_url_kwarg': 'version_pk', }, { 'lookup_field': 'document_version.document.pk', 'lookup_url_kwarg': 'pk', } ), view_name='rest_api:documentversion-detail' ) class BaseSignSerializer(serializers.HyperlinkedModelSerializer): passphrase = serializers.CharField( help_text=_( 'The passphrase to unlock the key and allow it to be used to ' 'sign the document version.' ), required=False, write_only=True ) class DetachedSignatureSerializer(BaseSignatureSerializer): url = MultiKwargHyperlinkedIdentityField( view_kwargs=( { 'lookup_field': 'document_version.document.pk', 'lookup_url_kwarg': 'document_id', }, { 'lookup_field': 'document_version_id', 'lookup_url_kwarg': 'document_version_id', }, { 'lookup_field': 'pk', 'lookup_url_kwarg': 'detached_signature_id', }, ), view_name='rest_api:detachedsignature-detail' ) class Meta: extra_kwargs = { 'signature_file': {'write_only': True}, } fields = ( 'date', 'document_version_url', 'key_id', 'signature_file', 'signature_id', 'public_key_fingerprint', 'url' ) model = DetachedSignature read_only_fields = ('key_id',) def create(self, validated_data): validated_data['document_version'] = self.context['document_version'] return super(DetachedSignatureSerializer, self).create( validated_data=validated_data ) class EmbeddedSignatureSerializer(serializers.HyperlinkedModelSerializer): document_version_url = MultiKwargHyperlinkedIdentityField( view_kwargs=( { 'lookup_field': 'document_version_id', 'lookup_url_kwarg': 'version_pk', }, { 'lookup_field': 'document_version.document.pk', 'lookup_url_kwarg': 'pk', } ), view_name='rest_api:documentversion-detail' ) url = MultiKwargHyperlinkedIdentityField( view_kwargs=( { 'lookup_field': 'document_version.document.pk', 'lookup_url_kwarg': 'document_id', }, { 'lookup_field': 'document_version_id', 'lookup_url_kwarg': 'document_version_id', }, { 'lookup_field': 'pk', 'lookup_url_kwarg': 'embedded_signature_id', }, ), view_name='rest_api:embeddedsignature-detail' ) passphrase = serializers.CharField(required=False, write_only=True) class Meta: fields = ( 'date', 'document_version_url', 'key_id', 'signature_id', 'passphrase', 'public_key_fingerprint', 'url' ) model = EmbeddedSignature def create(self, validated_data): key_id = validated_data.pop('key_id') passphrase = validated_data.pop('passphrase', None) key_queryset = AccessControlList.objects.restrict_queryset( permission=permission_key_sign, queryset=Key.objects.all(), user=self.context['request'].user ) try: key = key_queryset.get(fingerprint__endswith=key_id) except Key.DoesNotExist: raise ValidationError( { 'key_id': [ 'Key "{}" not found.'.format(key_id) ] }, code='invalid' ) signature = EmbeddedSignature.objects.sign_document_version( document_version=self.context['document_version'], key=key, passphrase=passphrase, user=self.context['request'].user ) return signature class SignDetachedSerializer(BaseSignatureSerializer, BaseSignSerializer): class Meta: fields = ( 'date', 'document_version_url', 'key_id', 'signature_id', 'passphrase', 'public_key_fingerprint', 'url' ) model = DetachedSignature def sign(self, key_id, passphrase): key_queryset = AccessControlList.objects.restrict_queryset( permission=permission_key_sign, queryset=Key.objects.all(), user=self.context['request'].user ) try: key = key_queryset.get(fingerprint__endswith=key_id) except Key.DoesNotExist: raise ValidationError( { 'key_id': [ 'Key "{}" not found.'.format(key_id) ] }, code='invalid' ) return DetachedSignature.objects.sign_document_version( document_version=self.context['document_version'], key=key, passphrase=passphrase, user=self.context['request'].user ) class SignEmbeddedSerializer(SignDetachedSerializer): class Meta: fields = ( 'date', 'document_version_url', 'key_id', 'signature_id', 'passphrase', 'public_key_fingerprint', 'url' ) model = EmbeddedSignature def sign(self, key_id, passphrase): key_queryset = AccessControlList.objects.restrict_queryset( permission=permission_key_sign, queryset=Key.objects.all(), user=self.context['request'].user ) try: key = key_queryset.get(fingerprint__endswith=key_id) except Key.DoesNotExist: raise ValidationError( { 'key_id': [ 'Key "{}" not found.'.format(key_id) ] }, code='invalid' ) return EmbeddedSignature.objects.sign_document_version( document_version=self.context['document_version'], key=key, passphrase=passphrase, user=self.context['request'].user )