Быстрый старт

Назначение и архитектура JC-WebClient

JC-WebClient представляет из себя приложение на основе технологии локального Web-сервера, которое работает на стороне клиента. Приложение:

  • принимает локальные HTTPS-запросы от браузера;
  • на основе этих запросов отправляет команды токену и/или Антифрод-терминалу либо выполняет программные функции;
  • возвращает результат работы в браузер.

JC-WebClient поддерживает:

  • все популярные платформы: Microsoft Windows, macOS, Linux;
  • все популярные браузеры: Google Chrome, Opera, Mozilla Firefox, Яндекс.Браузер, Apple Safari, Microsoft IE, Microsoft Edge, Спутник.

Архитектура JC-WebClient приведена на рисунке ниже:

../../../../_images/webclient4.png

Основные компоненты JC-WebClient:

  • Локальный Web-сервер
    • обеспечивает взаимодействие между Web-страницей и токеном/Антифрод-терминалом по протоколу HTTPS;
    • обеспечивает разделение PC/SC контекстов для различных вкладок браузера.
  • Клиентский скрипт JCWebClient.js
    • предоставляет Web-страницам JavaScript API для работы с командами и методами JC-WebClient;
    • загружается на Web-страницу с локального Web-сервера;
    • при вызове из контекста страницы Web-приложения команд или методов объектов, реализованных в файле JCWebClient.js, управление передаётся на локальный Web-сервер и далее к токену.
  • Сервис мониторинга, выполненный в виде службы ОС
    • запускает локальный Web-сервер при загрузке ОС;
    • контролирует целостность локального Web-сервера;
    • перезапускает локальный Web-сервер в случае нештатных ситуаций/сбоев в ОС.

Поддерживаемые устройства

JC-WebClient поддерживает работу со следующими средствами электронной подписи (далее – токенами) в форм-факторах USB-токен или смарт-карта:

Средство электронной подписи В состав каких устройств входит

“Криптотокен 2 ЭП”

Будем далее называть токен GOST 2

  • JaCarta-2 ГОСТ
  • Комбинированные устройства JaCarta, включающие в себя токен GOST 2. Например, JaCarta-2 ГОСТ/PRO включает в себя:
    • Токен GOST 2 – средство ЭП для работы с российскими криптографическими алгоритмами (СКЗИ “Криптотокен 2 ЭП”)
    • Токен PRO – средство ЭП для работы с зарубежными криптографическими алгоритмами

Особенности интеграции JaCarta-2 ГОСТ

“Криптотокен ЭП”

Будем далее называть токен GOST

  • JaCarta ГОСТ
  • eToken ГОСТ
  • Комбинированные устройства JaCarta, включающие в себя токен GOST. Например:
    • JaCarta PKI/ГОСТ
    • JaCarta PRO/ГОСТ
    • JaCarta SE
    • eToken ГОСТ/USB с апплетом PRO
Токен PRO
  • JaCarta PRO
  • Комбинированные устройства JaCarta, включающие в себя токен PRO
  • eToken PRO (Java)
  • eToken ГОСТ/USB с апплетом PRO

В качестве доверенного Trust Screen-устройства JC-WebClient поддерживает устройство Антифрод-терминал – собственный продукт компании «Аладдин Р.Д.».

Пошаговое руководство по доработке Web-страниц

Подключение и инициализация JC-WebClient

Для возможности работы с JC-WebClient через JavaScript API необходимо последовательно выполнить следующие действия (полный пример первых 3-х пунктов представлен в разделе Начало работы):

  1. Загрузите скрипт JCWebClient.js с локального адреса: https://localhost:24738/JCWebClient.js. На данном этапе необходимо учесть ситуацию, если на ПК пользователя отсутствует JC-WebClient, поэтому для загрузки скрипта JCWebClient.js рекомендуется следовать следующему алгоритму:

    1.1. Средствами JavaScript попытайтесь асинхронно загрузить JCWebClient.js.

    1.2. Если скрипт загрузился успешно, то следует перейти к пункту 2, в противном случае - перейти к следующему шагу.

    1.3. Сообщите пользователю о необходимости установить JC-WebClient и предложите вариант с его установкой.

    Для этого параллельно основному процессу выполните следующее:

    1. Отобразите пользователю информационное сообщение о необходимости установить JC-WebClient. В этом же сообщении сообщите о том, что загрузка инсталлятора JC-WebClient на ПК пользователя начнётся автоматически, но если не началась в течение, например, 5 секунд, предложите нажать на специальную ссылку для скачивания инсталлятора с Web-сервера.

    2. Выполните автоматическую загрузку инсталлятора JC-WebClient на ПК пользователя с Web-сервера вашего приложения.

      Примечание

      Если пользователь работает на платформе macOS, то после установки потребуется перезагрузка ПК (инсталлятор JC-WebClient уведомит об этом).

      Примечание

      Если пользователь использует браузер Mozilla Firefox, то после установки потребуется перезапустить все его открытые экземпляры.

    1.4. Ожидайте N секунд.

    1.5. Средствами JavaScript повторно попытайтесь асинхронно загрузить JCWebClient.js в ожидании, что пользователь установил JC-WebClient.

    1.6. Если скрипт загрузился успешно, то следует перейти к пункту 2, в противном случае - вернитесь к пункту 1.4.

    Пример реализации алгоритма загрузки скрипта JCWebClient.js

    // 1. Загрузка скрипта JCWebClient.js
    getJCWebClient({
        onLoad: function() {
            // Скрипт JCWebClient.js загружен и модуль JCWebClient2 установлен
            console.log('JC-WebClient установлен');
        },
        onError: function(error) {
            // Скрипт JCWebClient.js не загружен
    
            this.onError = undefined; // очищаем callback для того, чтобы код ниже выполнился только самый первый раз
    
            // Отобразите пользователю информационное сообщение о необходимости установить JC-WebClient.
            // В этом же сообщении сообщите о том, что загрузка инсталлятора JC-WebClient на ПК пользователя
            // начнётся автоматически, но если не началась в течение, например, 5 секунд,
            // предложите нажать на специальную ссылку для скачивания инсталлятора с Web-сервера.
            console.log('Установите JC-WebClient !!!');
        }
    });
    
    /** Функция цикличной загрузки модуля JCWebClient2.
        Асинхронная функция.
    
        @param params - объект с callback-функциями:
            onLoad - функция срабатывает при успешной установке модуля JC-WebClient. Может быть вызвана только один раз;
            onError - функция срабатывает неудачной установке модуля JC-WebClient. Может быть вызвана несколько раз.
    */
    function getJCWebClient(params) {
        // Проверка наличия модуля JCWebClient2 на Web-странице
        if (typeof(JCWebClient2) !== 'undefined') {
            // Модуль JCWebClient2 установлен
            params.onLoad();
            return;
        }
    
        // Получение скрипта JC-WebClient
        getScript(
            'https://localhost:24738/JCWebClient.js',
            params.onLoad,
            function(error) {
                if(typeof(params.onError) === 'function') {
                    params.onError(error);
                }
    
                // Повторная попытка получения скрипта после 2-х секундного таймаута
                setTimeout(function() {
                    getJCWebClient(params);
                }, 2000);
            }
        );
    }
    
    /** Функция загрузки скрипта.
    
        @param src - адрес расположения скрипта;
        @param done - callback-функция, срабатывающая при успешной загрузки скрипта;
        @param fail - callback-функция, срабатывающая при неудачной загрузки скрипта.
    */
    function getScript(src, done, fail) {
        var parent = document.getElementsByTagName('body')[0];
    
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = src;
    
        if (script.readyState) {  // IE
            script.onreadystatechange = function () {
                if (script.readyState === "loaded" || script.readyState === "complete") {
                    script.onreadystatechange = null;
                    // На некоторых браузерах мы попадаем сюда и в тех случаях когда скрипт не загружен,
                    // поэтому дополнительно проверяем валидность JCWebClient2
                    if (typeof (JCWebClient2) === 'undefined') {
                        onFail("JCWebClient is invalid");
                    }
                    else {
                        done();
                    }
                }
                else if (script.readyState !== "loading") {
                    onFail("JCWebClient hasn't been loaded");
                }
            }
        }
        else {  // Others
            script.onload = done;
            script.onerror = function() {
                onFail("JCWebClient hasn't been loaded");
            };
        }
    
        parent.appendChild(script);
    
        function onFail(errorMsg) {
            parent.removeChild(script);
            fail(errorMsg);
        }
    }
    
  2. После успешной установки модуля JCWebClient2 инициализируйте его функцией initialize.

    // 2. Инициализация JC-WebClient
    JCWebClient2.initialize();
    
  3. Проверьте версию JC-WebClient.

    На данном этапе следует проверить, соответствует ли версия JC-WebClient пользователя той, которая поддерживается Вашим Web-приложением. Для этого рекомендуется следовать следующему алгоритму:

    3.1. Асинхронно получите версию JC-WebClient командой getJCWebClientVersion.

    3.2. Если версия поддерживается Вашим Web-приложением (т.е. Вы провели тестирование этой версии с Вашим Web-приложением), то следует перейти к пункту 4, в противном случае - перейти к следующему шагу.

    3.3. Сообщите пользователю о том, что для корректной работы Web-приложения необходима другая версия JC-WebClient и далее можете:

    1. прервать работу с пользователем;
    2. предложить установить необходимую версию JC-WebClient (аналогично пункту 1.3);
    3. дать возможность пользователю самому выбрать его дальнейшие действия (a или b).

    3.4. Ожидайте N секунд.

    3.5. Повторно асинхронно получите версию JC-WebClient командой getJCWebClientVersion в ожидании, что пользователь установил необходимую версию.

    3.6. Если версия поддерживается Вашим Web-приложением, то перезагрузите текущую Web-страницу, в противном случае - вернитесь к пункту 3.4.

    Пример реализации проверки версии JC-WebClient

    // 3. Цикличная проверка версии JC-WebClient
    checkJCWebClientVersion(function() {
        // Версия JC-WebClient корректна
        console.log('Версия JC-WebClient корректна. Продолжаем работу...');
    });
    
    /* Функция цикличной проверки версии JC-WebClient.
       Асинхронная функция.
    
       @param done - callback-функция, срабатывающая при успешной проверке версии JC-WebClient.
    */
    function checkJCWebClientVersion(done) {
        var failureCount = 0; // Счетчик некорректных версий
    
        // Начать проверку версии JC-WebClient
        checkVersion();
    
        // Внутренняя функция проверки версии JC-WebClient
        function checkVersion() {
            // Получение версии JC-WebClient
            JCWebClient2.getJCWebClientVersion({
                async: true,
                onResult: function(version, error) {
                    if(typeof(error) !== 'undefined') {
                        // Можно обработать ошибки в соответствии с бизнес-логикой
                        console.log('Ошибка получения версии JC-WebClient: ' + error);
                    }
    
                    // Проверка версии JC-WebClient
                    if(/* Условие некорректности version */) {
                        // Версия не подходит
                        ++failureCount;
    
                        if(failureCount === 1) {
                            // Сообщите пользователю о том, что для корректной работы Web-приложения
                            // необходима версия JC-WebClient, отличная от текущей.
                            // Это сообщение отобразится только самый первый раз
                            console.log('Обновите JC-WebClient !!!');
                        }
    
                        // Повторная проверка версии JC-WebClient после 2-х секундного таймаута
                        setTimeout(function() {
                            checkVersion();
                        }, 2000);
                        return;
                    }
    
                    if(failureCount !== 0) {
                        // Перезагрузить страницу, т.к. ранее был подключен JC-WebClient неподходящей версии
                        window.location.reload();
                        return;
                    }
    
                    // Версия JC-WebClient корректна
                    done();
                }
            });
        }
    }
    
  4. Рекомендуем подписаться на уведомления от JC-WebClient для отслеживания событий подключения/отключения токенов и изменения состояния аутентификации (см. Работа с событиями).

После описанных выше действий Web-страница готова к последующей работе с JC-WebClient.

Базовые команды для работы с токенами

При работе с USB-токенами и смарт-картами (устройствами) необходимо выбрать на устройстве криптографическое приложение (токен). На одном устройстве может быть несколько токенов. Различные токены обладают различной функциональностью: например, GOST и GOST 2 реализует российские криптоалгоритмы, а PRO – западные. Для работы с токенами в JC-WebClient API предусмотрены слоты.

  1. Для получения массива слотов всех токенов (в том числе Антифрод-терминала без смарт-карты), подключенных к ПК, используйте команду getAllSlots:

    var slots = JCWebClient2.getAllSlots();
    

    Например, если к ПК подключено устройство JaCarta PRO/ГОСТ (на нём 2 поддерживаемых токена – PRO и GOST), то команда getAllSlots вернёт массив из двух объектов с разными идентификаторами слотов: один – для PRO, второй – для GOST.

    Схема ниже иллюстрирует общий случай связи слотов с токенами и устройствами:

    ../../../../_images/webclient_slots1.png

    Из схемы видно, что при подключении нескольких устройств (USB-токен, смарт-карта в Антифрод-терминале) каждый токен устройства (а также Антифрод-терминал без смарт карты) будет закреплен за отдельным слотом, которые используются как идентификаторы в JC-WebClient API.

  2. После получения массива слотов выберите токен, с которым вы хотите продолжать работать. Используйте команду getTokenInfo для получения информации о токене. Отсортировать массив токенов по их типу можно следующим образом:

    var TokenPRO = [];
    var TokenGOST = [];
    var TokenGOST2 = [];
    var AntifraudWithoutSmartCard = [];
    
    for (i = 0; i < slots.length; i++) {
       var slot = slots[i];
    
       // Определяем антифрод-терминал без смарт-карты
       if (typeof(slot.reader) !== 'undefined'
          && slot.reader.type === JCWebClient2.Vars.ReaderType.antifraud
          && slot.tokenExists === false) {
            AntifraudWithoutSmartCard.push(slot);
            continue;
       }
    
       // Получаем информацию о токене
       try {
         var tokenInfo = JCWebClient2.getTokenInfo({
            args: {
               tokenID: slot.id
            }
         });
    
         switch(tokenInfo.type) {
            case JCWebClient2.Vars.TokenType.pro: {
               TokenPRO.push(slot);
               break;
            }
            case JCWebClient2.Vars.TokenType.gost: {
               TokenGOST.push(slot);
               break;
            }
            case JCWebClient2.Vars.TokenType.gost2: {
               TokenGOST2.push(slot);
               break;
            }
         }
       }
       catch(error) {
          console.error("Error: " + error);
       }
    }
    
  3. Далее получите информацию о сертификатах, загруженных на токен. Для этого используйте следующие команды:

    1. getContainerList – получение списка контейнеров;
    2. getStandaloneCertificateList – получение списка автономных сертификатов;
    3. getCertificateBody - получение сертификата с токена;
    4. parseX509Certificate – парсинг сертификата.
  4. Полученную о сертификатах информацию необходимо отфильтровать и

    1. либо выбрать сертификат для работы с системой автоматически на основе заданных в Web-приложении фильтров и критериев;
    2. либо предоставить пользователю возможность выбрать сертификат из отфильтрованного списка, который он хочет использовать для работы с системой.
  5. После выбора сертификата, необходимо аутентифицироваться на токене с помощью PIN-кода пользователя. Без аутентификации токен будет работать в гостевом режиме с ограниченным функционалом: нельзя генерировать ключевые пары, создавать / изменять / удалять объекты на токене, создавать подпись и т.д. Для аутентификации необходимо запросить у пользователя PIN-код пользователя и использовать его при выполнения команды bindToken.

  6. После успешной аутентификации токен переходит в режим пользователя, все пользовательские операции становятся доступными.

  7. Узнать в каком режиме работает токен можно:

    1. с помощью команды getLoggedInState;
    2. с помощью события loginStateChangedEvent.
  8. Для более подробного описания работы с командами см. раздел Выполнение команд.

  9. С дополнительными примерами работы с токеном можно ознакомиться в разделе Примеры.

Разделение контекста между вкладками браузера

В JC-WebClient реализовано разделение контекста (сеансов работы с токеном) при работе из различных вкладок браузера. Это означает, что сеанс работы с токеном в режиме пользователя, установленный из одной вкладки, недоступен для других вкладок этого или другого браузера.

Контекст по умолчанию сохраняется при переходе с одной страницы на другую в рамках одной и той же вкладки браузера, а также при обновлении страницы (нажатие клавиши F5).

JC-WebClient предоставляет возможность явного указания на необходимость обнуления контекста при выходе за пределы данной Web-страницы. Для этого установите на этой Web-странице значение параметра JCWebClient2.saveSession в false:

JCWebClient2.saveSession = false;

Указанное значение параметра будет действовать только в пределах данной Web-страницы.

В JC-WebClient реализован таймаут в размере 1 минуты, по истечении которого контекст автоматически обнуляется, если приложение определило, что Web-страница перестала отвечать. При этом также удаляется и сеанс работы с токеном. Это произойдёт, например, в следующих случаях:

  • после закрытии Web-страницы (в том числе средствами DOM и jQuery) или браузера;
  • после перехода в данной вкладке на любую другую Web-страницу, которая не поддерживает работу с JC-WebClient.

Примечание

Если в текущем сеансе работы с токеном был введён PIN-код, т.е. состояние аутентификации токена выше, чем JCWebClient2.Vars.AuthState.notBinded, то после обнуления контекста состояние станет равно JCWebClient2.Vars.AuthState.notBinded, т.е. PIN-код потребуется вводить заново.

Более детальная информация по работе с JC-WebClient представлена в следующих разделах:

Руководство по работе с SDK

Функциональность JC-WebClient API

Особенности интеграции JaCarta-2 ГОСТ

Примеры

Справочник API