1С, Linux
Сервер для ЭЦП на Node.js
Author
NMitin
Date Published

Задача отправить из 1С на сервер документ и в ответ получить в Base64 этот документ и открепленную подпись CAdES-BES.
На ОС MX Linux установлена демо-версия КриптоПро CSP.
Скрипт сервера:
1const express = require('express');2const fs = require('fs');3const { execFile } = require('child_process');4const app = express();5const port = 3000;67// Включаем приём необработанных данных8app.use(express.raw({ type: '*/*', limit: '10mb' }));910app.post('/sign', (req, res) => {11 const thumbprint = req.headers['thumbprint'];1213 if (!thumbprint) {14 return res.status(400).send({ error: 'Не указан заголовок thumbprint' });15 }1617 const inputPath = '/tmp/input.cda';18 const sigPath = '/tmp/output.sig';1920 // Сохраняем тело запроса в файл21 fs.writeFileSync(inputPath, req.body);2223 const cryptcpPath = '/opt/cprocsp/bin/amd64/cryptcp';24 const args = [25 '-sign',26 '-detached',27 '-der',28 '-dn',29 '-add',30 '-cert',31 '-strict',32 '-thumbprint',33 thumbprint,34 inputPath,35 sigPath36 ];3738 execFile(cryptcpPath, args, (err, stdout, stderr) => {39 if (err) {40 console.error('Ошибка при подписи:', stderr.toString());41 return res.status(500).send({ error: stderr.toString() });42 }4344 const doc64 = fs.readFileSync(inputPath).toString('base64');45 const sig64 = fs.readFileSync(sigPath).toString('base64');4647 fs.unlinkSync(inputPath);48 fs.unlinkSync(sigPath);4950 res.send({51 Документ64: doc64,52 Подпись64: sig6453 });54 });55});5657app.listen(port, () => {58 console.log(`CAdES-sign server listening at http://localhost:${port}`);59});60
Теперь обработка для тестирования.
Реквизиты : ПутьКФайлу, Документ64, Подпись64 - строковые.
Код модуля формы:
12&НаКлиенте3Процедура ПодписатьДокументНаNodeJS(Команда)45 Если Не ЗначениеЗаполнено(ПутьКФайлу) Тогда6 ПоказатьПредупреждение(,"Файл не выбран.");7 Возврат;8 КонецЕсли;910 // Помещаем файл во временное хранилище11 Двоичные = Новый ДвоичныеДанные(ПутьКФайлу);12 АдресХранилища = ПоместитьВоВременноеХранилище(Двоичные);1314 // Запрос отпечатка15 Отпечаток = "ОтпечатокПоУмолчанию_Base64";16 Если Не ВвестиСтроку(Отпечаток, "Введите отпечаток сертификата (без пробелов):", 0, Ложь) Тогда17 Возврат;18 КонецЕсли;1920 // Передаём на сервер21 Результат = ПодписатьНаСервере(АдресХранилища, Отпечаток);2223 Если ТипЗнч(Результат) = Тип("Структура") Тогда24 Текст = "Документ64: " + Лев(Результат.Документ64, 100) + "...";25 Текст = Текст + Символы.ПС + "Подпись64: " + Лев(Результат.Подпись64, 100) + "...";26 Сообщение = Новый СообщениеПользователю;27 Сообщение.Текст = Текст;28 Сообщение.Сообщить();29 Иначе30 ПоказатьПредупреждение(,"Ошибка: " + Результат);31 КонецЕсли;3233КонецПроцедуры343536&НаСервере37Функция ПодписатьНаСервере(АдресХранилища, Отпечаток)3839 Попытка40 ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресХранилища);41 Если ДвоичныеДанные = Неопределено Тогда42 Возврат "Не удалось получить данные из временного хранилища.";43 КонецЕсли;4445 HTTP = Новый HTTPСоединение("localhost", 3000);4647 Запрос = Новый HTTPЗапрос("/sign");48 Запрос.Заголовки.Вставить("thumbprint", Отпечаток);49 Запрос.Заголовки.Вставить("Content-Type", "application/octet-stream");505152 Запрос.УстановитьТелоИзДвоичныхДанных(ДвоичныеДанные);5354 Ответ = HTTP.ОтправитьДляОбработки(Запрос);5556 Если Ответ.КодСостояния <> 200 Тогда57 Возврат "Ошибка HTTP: " + Ответ.КодСостояния ;58 КонецЕсли;59 JSON = Ответ.ПолучитьТелоКакСтроку();6061 Чтение = Новый ЧтениеJSON;62 Чтение.УстановитьСтроку(JSON);6364 Результат = ПрочитатьJSON(Чтение, , , , , ЭтотОбъект);6566 Исключение67 Возврат "Ошибка соединения: " + ОписаниеОшибки();68 КонецПопытки;69 Документ64 = Результат.Документ64;70 Подпись64 = Результат.Подпись64;71КонецФункции727374&НаКлиенте75Процедура ПутьКФайлуНачалоВыбора(Элемент, ДанныеВыбора, ВыборДобавлением, СтандартнаяОбработка)76 Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);77 Диалог.Фильтр = "XML-файлы (*.xml)|*.xml";78 Диалог.Заголовок = "Выберите документ XML";7980 Если Диалог.Выбрать() Тогда81 ПутьКФайлу = Диалог.ПолноеИмяФайла;82 Сообщить("Выбран файл: " + ПутьКФайлу);83 КонецЕсли;8485КонецПроцедуры86