Реализация собственного штампа электронной подписи

Web-клиент предоставляет возможность печати основных файлов карточки Документ со штампом электронной подписи (ЭП), если для подписания использовался сертификат.

При печати файла со штампом создаётся его PDF-версия, в которую отдельным блоком добавляется изображение штампа ЭП.

Программист может реализовать собственный способ формирования штампов ЭП. Для этого нужно разработать серверное расширение с генератором изображений.

Генератор изображений — класс, реализующий интерфейс IImageGenerator — интерфейс. Данный интерфейс определяет общие функции генераторов изображений: проверка возможности генерации изображения и формирования изображений. Штамп ЭП является частным случаем изображения, которое может быть сгенерировано IImageGenerator.

Возможность использования компонента IImageGenerator для генерации штампов ЭП проверяется по возвращаемому значению функции IImageGenerator.IsAllowed: если реализация поддерживает генерацию штампов, функция должна возвращать true, когда в generatorType передано значение ImageGeneratorType.ElectronicSignature.

Ниже приведён код примера генератора штампов.

public class SimpleImageGenerator : IImageGenerator
{
    private const int imageWidth = 100; (1)
    private readonly ServiceHelper serviceHelper;

    public SimpleImageGenerator(IServiceProvider serviceProvider)
    {
        serviceHelper = new ServiceHelper(serviceProvider);
    }

    public bool IsAllowed(SessionContext sessionContext, ImageGeneratorType generatorType, Guid cardId, Guid fileCardId, Guid? fileVersionId = null) (2)
    {
        return generatorType == ImageGeneratorType.ElectronicSignature; (3) (4)
    }

    public Image[] Generate(SessionContext sessionContext, ImageGeneratorType generatorType, Guid cardId, Guid fileCardId, Guid? fileVersionId = null) (5)
    {
        var generatedImages = new List<Image>();

        var stampModels = serviceHelper.DocumentSignatureService.GetStampSignatureModel(sessionContext, cardId, fileCardId, fileVersionId); (6)

        foreach (var stampModel in stampModels) (7)
        {
            if (stampModel.Certificate == null) continue;

            var certificateNumber = stampModel.Certificate.GetSerialNumberString();
            var notBefore = stampModel.Certificate.NotBefore;
            var owner = stampModel.Certificate.GetNameInfo(X509NameType.SimpleName, false); (8)

            var html = String.Format(Resources.StampHtml, Resources.Css, certificateNumber, owner, notBefore); (9)
            var htmlToImageConv = new NReco.ImageGenerator.adocToImageConverter(); (10)
            htmlToImageConv.Width = imageWidth;

            using (var pngStream = new MemoryStream())
            {
                htmlToImageConv.GenerateImage(html, "png", pngStream);
                generatedImages.Add(Image.FromStream(pngStream));
            }
        }

        return generatedImages.ToArray(); (11)
    }
}
1 Ширина изображения.
2 Реализация метод IImageGenerator.IsAllowed.
3 Метод должен возвращать true, если generatorType имеет значение ImageGeneratorType.ElectronicSignature.
4 Здесь могут содержаться дополнительные проверки.
5 Реализация метода IImageGenerator.Generate.
6 Модели с данными подписей на файле документа с fileCardId получаем с помощью сервиса DocumentSignatureService.

Может использоваться собственная реализация способа получения данных о подписях.

7 Штамп формируем для каждой подписи.
8 Подготавливаем данные для штампа: номер, срок действия и владелец сертификата.
9 Формируем изображение штампа.
10 В данном примере изображение формируется путём преобразования HTML в .png с помощью сторонней библиотеки NReco.

В собственной реализации могут использоваться любые другие способы генерации изображений из текста.

11 Метод возвращает изображения штампов всех электронных подписей.

Пример html-кода получаемого из ресурса Resources.StampHtml:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Docsvision mail client email</title>
		<style type="text/css" media="all">
            {0}
		</style>
		</head>

        <body>
		<div class="stamp">
            <div class="top">
				<div class="main">
					Документ подписан<br /> электронной подписью
				</div>
			</div>
			<table class="bottom">
				<tr>
					<td>Сертификат:</td>
					<td>{1}</td>
				</tr>
				<tr class="bold">
					<td>Владелец:</td>
					<td>{2}</td>
				</tr>
				<tr>
					<td>Действителен:</td>
					<td>{3}</td>
				</tr>
			</table>
		</div>
	</body>
</html>

Пример стилей из ресурса Resources.Css:

.stamp {
    display: inline-block;
    font-family: Arial, serif;
    padding: .5rem;
    border: 3px double blue;
    border-radius: 6px;
    color: blue;
}
.top {
    display: flex;
    justify-content: space-around;
    border-bottom: 2px dotted blue;
    padding-bottom: .3rem;
}
.main {
    font-size: .75rem;
    text-transform: uppercase;
    display: inline-block;
}
.bottom {
    margin-top: 3px;
    font-size: 0.64rem;
    white-space: nowrap;
    line-height: 100%;
}
.bottom td {
    padding: 0 1px;
}
.bold {
    font-weight: bold;
}

Разработанный генератор изображений должен быть зарегистрирован в ядре серверного расширения в методе InitializeContainer:

public override void InitializeContainer(ContainerBuilder containerBuilder)
{
    containerBuilder.RegisterOrderedType<SimpleImageGenerator, IImageGenerator>();
}
Если в Web-клиенте зарегистрировано несколько реализаций IImageGenerator с поддержкой ImageGeneratorType.ElectronicSignature, будет использоваться реализация из последнего загруженного серверного расширения.