Skip to main content

An application for cryptographic signing of models, files and etc.

Project description

An application for cryptographic signing of models, files and etc.

Detailed documentation is in the “docs” directory.

Quick start

  1. Add sign manager app to project app list in project settings:

    INSTALLED_APPS = [
        ...
        'sign_manager'
    ]
    
  2. Setup simple wizard app (see repo README).

  3. Add tray template to base template:

    {% include 'sign_manager/tray.html' with tray_id='main_sign_manager' only %}
    
  4. Add static files (css and js):

    <script src="{% static 'sign_manager/js/tray.js' %}"></script>
    <script src="{% static 'sign_manager/js/api.js' %}"></script>
    
    <link rel="stylesheet" href="{% static 'sign_manager/css/tray.css' %}">
    
  5. Add classes for sign modal:

    class CryptoProWizardStepMixin(SignManagerMixin, WizardModalStepMixin):
        """
        Common class for CryptoPro modal
        """
    
        template_name = 'simple_wizard/crypto_pro_sign_modal.html'
        cache_step = False
        buttons = [
            BaseWizardButton(
                load_step='crypto_pro_step',
                method='post',
                always_fetch=True,
                title='Apply',
                css_classes=['btn btn-primary', 'js-crypto_pro_start_sign']
            )
        ]
    
        def get_buttons(self) -> list:
            buttons = super().get_buttons()
            crypto_pro_debug = getattr(settings, 'CRYPTO_PRO_DEBUG', False)
            if crypto_pro_debug and len(buttons) == 1:
                buttons.append(
                    BaseWizardButton(
                        load_step='crypto_pro_step',
                        method='post',
                        always_fetch=True,
                        title='Skip sign',
                        css_classes=['btn btn-primary', 'js-crypto_pro_skip_sign']
                    )
                )
            return buttons
    
        def set_sign_initial_data(self) -> List[BaseSignatureObject]:
            # set initial data for create data-formset
            test_model = TestModel.objects.filter(pk=self.kwargs.get('pk')).first()
            test_model.set_status()  # status set must be without commit
            initial_data = [XMLSignatureObject(object_for_sign=test_model)]
            return initial_data
    
        def process_view(self) -> None:
            # make all operations in this method
            pass
    
    
    class CryptoProWizardView(WizardBaseView):
        """
        View for creating wizard with CryptoPro sign
        """
    
        management_url_pattern = 'test_app:wizard_management'
        common_title = 'CryptoPro'
    
        ...  # see simple wizard README
    
        class ThirdStep(CryptoProWizardStepMixin, TemplateView):
            """
            CryptoPro modal
            """
    
            unique_name = 'crypto_pro_step'
    
            def restore_objects_from_cache(self) -> None:
                # you can restore cached objects before sign save (in some cases it
                # necessary because some data can be changed on result save).
                # put some code here for restoring models states.
                # you can use built-in CacheManager method - "deserialize_object()" -
                # just call "save()" for proxy-object (see method).
    
                pass
    

6. Prepare your model (add “AbstractSignManager” in superclasses). You can create custom “AbstractSignManager” through defining variable “SIGN_MANAGER_ABSTRACT_MODEL_CLASS” in project settings:

...

AbstractSignManager = get_sign_manager_abstract_model_class()

...

class TestModel(AbstractSignManager):

    ...

    def serialize_for_sign(self) -> Union[bytes, str]:
        # change serialization if needed
        xml = super().serialize_for_sign()
        return base64.b64encode(xml.encode()).decode('utf-8')

    def get_stages_number(self) -> int:
        # setup chucks total number (here you can check file size if you want
        # sign file and etc. and recognize optimal stages number)
        # in this example we will sign just a string in base64 encoding
        # 10 steps - 10 requests to the server to receive necessary data
        return 10

    def get_data_chunk(self, stage: int, stages_num: int) -> str:
        # here you can provide logic for chunks creation.
        # in this example we use built-in method based on slicing for small simple strings.
        # for big files use file.read(bytes_to_read) or another approach.
        # stage - current stage of stages_num - this info can help in data-chucks creation
        return self.get_data_chunk_for_simple_string(stage, stages_num).
  1. Setup Queue handler:

    class SignQueue(SignManagerQueueView):
        """
        Handler-view for sending data for sign to js script
        """
    
        pass
    
  2. Setup queue-handler url and wizard url:

    app_name = 'test_app'
    
    urlpatterns = [
        ...
    
        path('wizard-management/<step_to_load>/test_model/<int:pk>/', CryptoProWizardView.as_view(),
            name='wizard_management'),
        path('sign-queue/', SignQueue.as_view(), name='sign_queue')
    ]
    
  3. Initialize js handlers (wizard and signer):

    const django_modal_wizard = new DjangoModalWizard(
        '#wizard-modal',
        '.js-wizard_modal_content',
        '.js-load_wizard',
        '.js-close_wizard'
    );
    django_modal_wizard.initSignals();
    
    const sign_manager = new BTCCryptoProClientManager();
    sign_manager.ask_url = '/test-app/sign-queue/';
    sign_manager.form_elements_container_selector = '.js-wizard_modal_content';
    sign_manager.initSignals();
    
    # fill certificates choices on crypto pro modal load
    $(document).on('django-wizard:step-loaded', function (event, step_to_load, method_name, data) {
        if (step_to_load === 'crypto_pro_step') {
            sign_manager.fillCertificatesSelect();
            event.preventDefault();
        }
    });
    
    # customize handler if needed - all attributes can be redefined
    
  4. Migrate:

    ./manage.py migrate
    

11. For customizing Queue logic you can override “CacheManager” class by defining variable “SIGN_MANAGER_CACHE_MANAGER_CLASS” in project settings:

class CustomCacheManager(CacheManager):
    """
    Custom class for queue control (big files serialization and etc.)
    """
    ...

# in project settings:
...

SIGN_MANAGER_CACHE_MANAGER_CLASS = 'test_app.CustomCacheManager'

Example

https://user-images.githubusercontent.com/33987296/71226909-8fe60a00-22ee-11ea-8c1a-d73b6a91a022.jpg

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for btc-sign-manager, version 0.6
Filename, size File type Python version Upload date Hashes
Filename, size btc-sign-manager-0.6.tar.gz (23.1 kB) File type Source Python version None Upload date Hashes View hashes

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page