Начало работы с подписями

В системе реализовано взаимодействие с криптопровайдерами, выполняющими функции подписания пользовательских данных: КриптоПро, НУЦ и другими. Кроме того, пользовательские скрипты позволяют выполнять подписание данных с помощью других облачных криптопровайдеров. Для работы с данным функционалом необходимо настроить электронную подпись.

Внутренняя подпись

Для получения данных и контроля изменений в системе можно получить внутреннюю подпись данных. Данная подпись не является юридически значимой. Ее предназначение — контроль изменений в приложении и фиксация версии данных элемента приложения. С подписью предоставляются также и данные, вычисленные по настройкам подписи приложения. В системе предусмотрено получение внутренней подписи для атрибутов элемента любого приложения и для файла в приложении типа Документ. Для получения внутренней подписи необходимо хранить приложение в контексте или найти его с помощью объектов Global или Namespace:

async function workWithDataSigns(): Promise<void> {
    // Получение приложения из контекста
    // document — приложение типа Документ
    const app = Context.data.document!;

    // Получение данных приложения
    const appData = await app.fetch();

    // Получение подписей
    const innerSigns = await appData.getDataSigns();

    // Найдем внутреннюю подпись атрибутов, чтобы подписать данные с помощью криптопровайдера
    const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
    if (!attributesInnerSign) {
        throw new Error('Внутренняя подпись не найдена');
    }
}

Загрузка полученной подписи в систему

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

async function saveSign(): Promise<void> {
    // SignProvider — пример криптопровайдера
    // Включает в себя один метод вычисления подписи из данных
    const signProvider = new SignProvider();
    
    // Получение подписи для атрибутов
    const signData = signProvider.sign(attributesInnerSign.body);
    
    const newSign: NewSign = {
        // Подпись в формате base64
        sign: signData;
        // Тип подписи в зависимости от того, что необходимо подписать — attributes или file
        signType: attributesInnerSign.type;
        // Код провайдера
        codeProvider: 'signProvider';
        // ID файла в формате base64
        body: attributesInnerSign.body,
        // Хеш подписанных данных (необходим для идентификации версии подписываемых данных)
        hash: attributesInnerSign.hash,
    }
     
    await appData.uploadSign(newSign);
}

Получение файла подписанных атрибутов и файла подписи

Для получения содержимого подписанных атрибутов и самой подписи используются методы createAttributesFile и EntitySign.createSignFile. Для того чтобы получить EntitySign, необходимо получить историю подписей элемента приложения. Для нахождения необходимой версии подписи в истории можно воспользоваться внутренней подписью приложения:

async function getSignsFiles(): Promise<void> {
    // Получение приложения типа Документ из контекста пользовательского скрипта
    const app = Context.data.document!;
    // Получение данных приложения
    const appData = await app.fetch();
    // Получение истории подписей элемента приложения
    const signsHistory = await appData.getSignHistory();
    // Получение внутренних подписей
    const innerSigns = await appData.getDataSigns();

    // Найдем внутреннюю подпись атрибутов, чтобы подписать данные с помощью криптопровайдера
    const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
    if (!attributesInnerSign) {
        throw new Error('Внутренняя подпись не найдена');
    }

    // Найдем в архиве подпиcей подписи последней версии элемента приложения
    const signs = signsHistory.find(signs => signs.hash === attributesInnerSigns.hash);
    if (!signs) {
        throw new Error('Данная версия не подписана');
    }

    const dataSign = signs.signs[0];

    const attributesFile = await dataSign.createAttributesFile();
    const signFile = await dataSign.createSignFile();
}

Получение детальной информации о подписи

В системе можно получить детальные данные о подписи, включающие в себя:

  • информацию о самой подписи;
  • содержимое подписи;
  • информацию о публичном ключе, с помощью которого выполнено подписание данных;
  • подписанные данные.

Для получения данных необходимо вызвать метод EntitySign.getDetails. Данный метод позволяет получить детальные данные о подписи. Рассмотрим ситуацию, когда в пользовательском скрипте необходимо определить, юридическим или физическим лицом выполнена подпись. Для этого необходимо получить подпись из истории и вызвать метод EntitySign.getDetails. После получения данных необходимо проанализировать содержимое сертификата:

async function whoMadeSign(): Promise<void> {
    // Получение приложения типа Документ из контекста пользовательского скрипта
    const app = Context.data.document!;
    // Получение данных приложения
    const appData = await app.fetch();
    // Получение истории подписей приложения
    const signsHistory = await appData.getSignHistory();
    // Получение последней подписи
    const sign = signsHistory[0].signs[0];
    // Получение информации о подписи
    const signDetails = await sign.getDetails();
    
    // Если заполнено одно из этих полей, то подпись выполнена юридическим лицом
    // Также для таких проверок можно использовать и другие поля сертификата, в зависимости
    // от провайдера, выдавшего цифровую подпись
    const orgField = signDetails.subject['O'] || signDetails.subject['OU'];
    
    if (orgField !== '') {
        // Подпись для юридического лица
    } else {
        // Подпись для физического лица
    }
    
}

Также вы можете получить информацию о сертификатах подписей, включающие в себя: данные об УЦ, кому выдан сертификат и время его действия.

Пример скрипта для получения информации о сертификатах подписей, истекающих в течение месяца:

async function signWithSoonExpiredCerts (): Promise<void> {
    // Получение текущего пользователя
    const user = await System.users.getCurrentUser();
    // Дата, не позднее которой истекает действие сертификата подписи 
    const expiredDate = new Datetime().addDate(0, 1, 0);
    // Получение подписей пользователя
    const digitalSigns = await System.signs.digitalSigns.search().where(sign => sign.__createdBy.eq(user)).all();
    // Получение подписей, сертификаты которых истекают в течение следующего месяца 
    const expiredSigns = digitalSigns.filter(sign => sign.data.validUntilAt?.beforeOrEqual(expiredDate));

    // Запись в переменную контекста информации о подписях с истекающими сертификатами
    Context.data.expiredcerts = 'Сертификаты, истекающие в течении месяца: ';
    for (let sign of expiredSigns) {
        const subjectName = sign.data.subject ? sign.data.subject['CN'] ?? 'имя неизвестно' : 'подписант неизвестен';
        Context.data.expiredcerts += `${sign.id} : ${subjectName},`;
    }

    return;
}