Предоставляет методы для работы со страницами PDF-документа.
Полное описание, параметры и ограничения
КоллекцияСтраницPDF (PDFPagesCollection)
КоллекцияСтраницPDF (PDFPagesCollection)
Доступен, начиная с версии 8.3.26.
Элементы коллекции:
СтраницаPDF
Для объекта доступен обход коллекции посредством оператора Для каждого … Из … Цикл. При обходе выбираются страницы документа PDF.
Возможно обращение к странице документа PDF посредством оператора [...]. В качестве аргумента передается .
Методы:
Индекс (IndexOf)
Количество (Count)
Получить (Get)
Описание:
Предоставляет методы для работы со страницами PDF-документа.
Доступность:
Тонкий клиент, веб-клиент, сервер, толстый клиент.
Использование в версии:
Доступен, начиная с версии 8.3.26.
Методическая информация
Практические примеры
Создать настоящий учебный PDF и разобрать страницу
Экспортируем таблицу Книга / 3 / 250 / 750 и читаем PDF обратно. Индекс коллекции начинается с нуля, номер страницы — с единицы.
Где и как запускать
Полный серверный общий модуль УчебныйPDF собственной учебной конфигурации; только собственные PDF-байты в памяти.
Подготовка
Отдельная собственная учебная база 8.5.1.1343: серверный общий модуль УчебныйPDF. Вставьте полный модуль одного урока и вызовите ВыполнитьПример() своей серверной командой.
Имя конфигурации должно быть УчебнаяКонфигурацияСинтаксиса. Все данные создаются кодом: строка Книга / 3 / 250 / 750 и собственные текстовые вложения.
Исходный PDF получается настоящим экспортом собственного ТабличныйДокумент в ПотокВПамяти. Никакого файла с неизвестным происхождением или рабочего печатного макета не требуется.
Чтение и повторная запись выполняются в памяти. Примеры не печатают, не обращаются к интернету и не меняют документы базы.
Проверки размеров, страниц и вложений не доказывают вид штампа или оттенки серого. Для визуального контроля используйте отдельный урок просмотра собственного PDF; этот серверный модуль окна не открывает.
Функция СоздатьСобственныеБайтыPDF()
Таблица = Новый ТабличныйДокумент;
Таблица.КодЯзыка = "ru";
Таблица.Область(1, 1).Текст = "СОБСТВЕННЫЙ УЧЕБНЫЙ ОБРАЗЕЦ";
Таблица.Область(2, 1).Текст = "Книга";
Таблица.Область(2, 2).Текст = "3";
Таблица.Область(2, 3).Текст = "250";
Таблица.Область(2, 4).Текст = "750";
Таблица.Область(1, 1, 2, 4).ЦветФона = Новый Цвет(255, 255, 210);
Таблица.Область(, 1, , 1).ШиринаКолонки = 45;
Поток = Новый ПотокВПамяти;
Попытка
Таблица.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Данные;
КонецФункции
Функция ПрочитатьСобственныйДокумент(Данные)
Поток = Данные.ОткрытьПотокДляЧтения();
Попытка
Документ = Новый ДокументPDF;
Документ.Прочитать(Поток);
Поток.Закрыть();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Документ;
КонецФункции
Процедура ВыполнитьПример() Экспорт
Данные = СоздатьСобственныеБайтыPDF();
Документ = ПрочитатьСобственныйДокумент(Данные);
Страницы = Документ.Страницы;
Сообщить(Данные.Размер() > 0);
Сообщить(Страницы.Количество() = Документ.КоличествоСтраниц());
Если Страницы.Количество() = 0 Тогда
ВызватьИсключение "В собственном PDF нет страниц";
КонецЕсли;
Первая = Страницы.Получить(0);
Сообщить(Первая.Номер = 1);
Сообщить(Страницы.Индекс(Первая) = 0);
Сообщить(Первая.Ширина > 0 И Первая.Высота > 0);
Сообщить(ТипЗнч(Первая.Ориентация) = Тип("Число"));
Сообщить(Первая.ПолеСверху >= 0 И Первая.ПолеСнизу >= 0);
Сообщить(Первая.ПолеСлева >= 0 И Первая.ПолеСправа >= 0);
Сообщить("Размер страницы, мм: " + Строка(Первая.Ширина) + " × " + Строка(Первая.Высота));
Сообщить("Угол, градусы: " + Строка(Первая.Ориентация));
Сообщить("Формат PDF: " + Строка(Документ.ТипФайла));
Сообщить(Документ.Вложения.Количество() = 0);
КонецПроцедурыРазбор по шагам
Создать табличный документ и экспортировать в поток. Получить ДвоичныеДанные вместе с закрытием исходного потока.
Открыть отдельный поток чтения, прочитать ДокументPDF и закрыть поток. Сам документ продолжает хранить прочитанные данные.
Сверить количество страниц двумя настоящими API. Проверить наличие хотя бы одной страницы перед Получить(0).
Прочитать номер, размеры, угол и четыре поля. Все свойства страницы только для чтения; мм и градусы — разные единицы.
Как проверить результат
Девять булевых проверок должны дать Истина. Получить(0).Номер = 1 и Индекс(Первая) = 0.
Выводятся реальные размеры и угол собственной страницы, а не зашитое предположение A4. Вложений исходного документа нет.
Ожидаемый результат
Полный путь от собственной таблицы к настоящему PDF и читаемому паспорту страницы.
На что обратить внимание
Количество страниц зависит от вывода таблицы, размеров и настроек; не переносите ожидание одной страницы на произвольный отчёт.
Ориентация страницы PDF — числовой угол, а не перечисление Портрет/Альбом и не Булево.
СтраницаPDF не имеет конструктора и изменяемых размеров. Коллекция страниц не имеет Добавить, Удалить или Очистить.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.
Асинхронно подписать свой PDF и получить реальные результаты проверки в тонком клиенте
Полный модуль собственной формы получает свои PDF-байты с сервера, использует явно подготовленный CurrentUser-ключ, ждёт подпись/запись/чтение и проверяет реальные Array/Certificate-результаты Promise. Ни Promise, ни выходные параметры синхронных overloads не подменяют готовый результат.
Где и как запускать
Полный модуль управляемой формы собственного тонкого Windows-клиента: PDF-операции с Ждать, отдельный полный supporting-серверный модуль для генерации своих байтов. В1С не запускался.
Подготовка
НОВАЯ пустая файловая учебная база УчебнаяАсинхроннаяПодписьPDF85 на8.5.1.1343, совместимость Не использовать. Только свои модуль и форма; без рабочих объектов, расширений, подписок/заданий. Запускать под ОТДЕЛЬНЫМ собственным Windows-пользователем или в отдельном учебном Windows-стенде без рабочих сертификатов. Не серверный кластер под служебной учётной записью.
Для будущей ручной подготовки отключите сеть учебного стенда. Все операции подписи локальны, TSA-массив в коде явно пуст. Команды создания ключа ниже НЕ выполнялись при подготовке справочника; они создают собственный сертификат и закрытый ключ в Личном текущего учебного Windows-пользователя.
Откройте Windows PowerShell в своём отдельном учебном профиле, не от администратора рабочего сервера. В одной и той же консоли вручную выполните последовательно только следующие четыре команды; не закрывайте её между командами. Провайдер Microsoft Enhanced RSA and AES Cryptographic Provider должен существовать и иметь Type24. CNG-провайдер по умолчанию не подставлять вместо него.
Ручная команда 1: $pdfTrainingId = [guid]::NewGuid().ToString("D")
Ручная команда 2: $pdfTrainingCert = New-SelfSignedCertificate -Type Custom -Subject ("CN=Syntax Guide PDF Own85 " + $pdfTrainingId) -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeySpec Signature -KeyAlgorithm RSA -KeyLength 2048 -KeyUsage DigitalSignature -HashAlgorithm SHA256 -KeyExportPolicy NonExportable -CertStoreLocation "Cert:\CurrentUser\My" -NotAfter (Get-Date).AddMonths(1)
Ручная команда 3: if (-not $pdfTrainingCert.HasPrivateKey) { throw "Own training private key was not created" }
Ручная команда 4: [pscustomobject]@{TrainingId=$pdfTrainingId;ThumbprintHex=$pdfTrainingCert.Thumbprint;OwnPrivateKey=$pdfTrainingCert.HasPrivateKey;Subject=$pdfTrainingCert.Subject}
Сохраните показанные TrainingId и ThumbprintHex для этой попытки. OwnPrivateKey должен быть True, Subject должен содержать только Syntax Guide PDF Own85 и ваш новый TrainingId. Ключ не экспортируется в PFX и не печатается. Сертификат самоподписанный и не добавляется в доверенные корневые.
Команды и различие legacy CSP/KeySpec=Signature сверены с официальной документацией Microsoft New-SelfSignedCertificate: https://learn.microsoft.com/en-us/powershell/module/pki/new-selfsignedcertificate?view=windowsserver2025-ps. Это документирование будущего учебного опыта, не выполненное создание ключа.
Учебный сертификат и ключ остаются в собственном Windows-профиле после закрытия1С; урок их автоматически не удаляет. Администратор отдельного стенда отвечает за его очистку после обучения. Не переносите опыт в рабочий профиль и не выдавайте закрытие формы за удаление ключа.
Ни PowerShell-команды, ни CryptoAPI/1С, ни AddSignature, ни GUI/сервер/ключи/подпись здесь не запускались. runtimeVerifiedScenarios=0.
Используйте именно тонкий Windows-клиент собственной файловой базы8.5.1.1343. В конфигурации разрешите синхронные вызовы расширений платформы/внешних компонент: сведения, инициализация CryptoAPI и поиск своего сертификата здесь синхронные. Асинхронны PDF-операции; это не обещание полностью неблокирующего криптографического стека.
Основной код теперь вставляется В МОДУЛЬ ФОРМЫ, не в серверный общий модуль. Своя управляемая форма: реквизиты МеткаСертификата85 Строка100, ОтпечатокHex85 Строка40, ПодтверждаюСвойСтенд Булево начально Ложь, Занято Булево начально Ложь, Отчёт Строка0. Поля с теми же путями; Занято не редактировать, Отчёт многострочный ТолькоПросмотр=Да. Команда/кнопка Выполнить, действие Выполнить. Вставьте весь основной модуль, сохранить/F7, открыть свою форму и скопировать фактические TrainingId/ThumbprintHex.
В общий серверный модуль УчебнаяАсинхроннаяПодписьPDF85 вставьте ТОЛЬКО supporting-модуль ниже. Сервер=Да, Вызов сервера=Да, Клиент=Нет, Глобальный=Нет, Привилегированный=Нет. Он проверяет свою пустую конфигурацию и экспортирует только собственную таблицу в байты. Подписание/ключевой контейнер работают у своего текущего Windows-клиента, не у учётной записи рабочего сервера.
Во время Ждать не закрывайте форму и не меняйте поля источника ключа. Метка/отпечаток копируются в локальные переменные до ожидания, Занято запрещает повторный старт; флаг очищается и при успехе, и при ошибке. Веб-/мобильный клиент и установка расширений не входят в этот опыт.
&НаКлиенте
Функция ПодготовитьСвойМенеджер()
Информация = СредстваКриптографии.ПолучитьИнформациюМодуляКриптографии("Microsoft Enhanced RSA and AES Cryptographic Provider", "", 24);
Если Информация = Неопределено Или ТипЗнч(Информация) <> Тип("ИнформацияМодуляКриптографии") Тогда
ВызватьИсключение "На своём Windows-стенде не найден требуемый провайдер";
КонецЕсли;
Если Информация.ТипМодуляКриптографии <> 24 Тогда
ВызватьИсключение "Нужен фактический CryptoAPI-провайдер типа24";
КонецЕсли;
АлгоритмSHA256 = "";
Для Каждого Алгоритм Из Информация.АлгоритмыХеширования Цикл
Если НРег(Алгоритм) = "sha256" Или НРег(Алгоритм) = "sha-256" Или Алгоритм = "2.16.840.1.101.3.4.2.1" Тогда
АлгоритмSHA256 = Алгоритм;
КонецЕсли;
КонецЦикла;
Если АлгоритмSHA256 = "" Тогда
ВызватьИсключение "Свой провайдер не подтвердил SHA256; другое имя не подставлять наугад";
КонецЕсли;
Менеджер = Новый МенеджерКриптографии("Microsoft Enhanced RSA and AES Cryptographic Provider", "", 24, ИспользованиеИнтерактивногоРежимаКриптографии.НеИспользовать);
Менеджер.АлгоритмХеширования = АлгоритмSHA256;
Менеджер.ВключениеСертификатовВПодпись = РежимВключенияСертификатовКриптографии.ВключатьСертификатСубъекта;
Менеджер.АдресаСерверовМетокВремени = Новый Массив;
Если Менеджер.АдресаСерверовМетокВремени.Количество() <> 0 Тогда
ВызватьИсключение "Урок не должен обращаться к внешнему серверу меток времени";
КонецЕсли;
Возврат Менеджер;
КонецФункции
&НаКлиенте
Функция НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex)
Если СтрДлина(ОтпечатокHex) <> 40 Тогда
ВызватьИсключение "Скопируйте весь SHA1-отпечаток из собственного PowerShell-опыта без пробелов";
КонецЕсли;
Отпечаток = ПолучитьДвоичныеДанныеИзHexСтроки(ОтпечатокHex);
Если Отпечаток.Размер() <> 20 Тогда
ВызватьИсключение "SHA1-отпечаток должен содержать20байт";
КонецЕсли;
Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты,
РасположениеХранилищаСертификатовКриптографии.ДанныеПользователяОС);
Сертификат = Хранилище.НайтиПоОтпечатку(Отпечаток);
Если Сертификат = Неопределено Или ТипЗнч(Сертификат) <> Тип("СертификатКриптографии") Тогда
ВызватьИсключение "В собственном текущем Windows-профиле не найден именно созданный учебный сертификат";
КонецЕсли;
Если Base64Строка(Сертификат.Отпечаток) <> Base64Строка(Отпечаток) Тогда
ВызватьИсключение "Найден не свой точный отпечаток";
КонецЕсли;
CN = Неопределено;
Если Не Сертификат.Субъект.Свойство("CN", CN) Тогда
ВызватьИсключение "Нет собственного CN учебного сертификата";
КонецЕсли;
Если CN <> "Syntax Guide PDF Own85 " + Метка Тогда
ВызватьИсключение "CN должен совпасть с собственной уникальной меткой подготовки ключа";
КонецЕсли;
Возврат Сертификат;
КонецФункции
&НаКлиенте
Функция ПодготовитьСвоюПодпись(Документ, Сертификат, Метка)
Если Документ.КоличествоСтраниц() = 0 Тогда
ВызватьИсключение "Нужен собственный PDF с реальной первой страницей";
КонецЕсли;
Страница = Документ.Страницы.Получить(0);
Если Страница.Ориентация <> 0 Или Страница.Ширина - Страница.ПолеСлева - Страница.ПолеСправа < 80
Или Страница.Высота - Страница.ПолеСверху - Страница.ПолеСнизу < 60 Тогда
ВызватьИсключение "Собственная неповёрнутая страница должна вместить штамп10/45/70/15мм";
КонецЕсли;
Описание = Новый ОписаниеПодписиPDF;
Описание.Имя = "СвояПодпись85_" + Метка;
Описание.Сертификат = Сертификат;
Описание.ТипПодписи = ТипПодписиPDF.Утверждающая;
Описание.БлокировкаДокумента = Ложь;
Описание.НомерСтраницы = 1;
Описание.Лево = 10;
Описание.Верх = 45;
Описание.Ширина = 70;
Описание.Высота = 15;
Возврат Описание;
КонецФункции
&НаКлиенте
Асинх Функция ПрочитатьСвоиБайтыАсинх(Данные)
Поток = Данные.ОткрытьПотокДляЧтения();
Попытка
Документ = Новый ДокументPDF;
Ждать Документ.ПрочитатьАсинх(Поток, "");
Исключение
ОшибкаОперации = ОписаниеОшибки();
Попытка
Поток.Закрыть();
Исключение
ОшибкаОперации = ОшибкаОперации + " Закрытие своего входного потока: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ОшибкаОперации;
КонецПопытки;
Поток.Закрыть();
Возврат Документ;
КонецФункции
&НаКлиенте
Асинх Функция ЗаписатьСвоиБайтыАсинх(Документ)
Поток = Новый ПотокВПамяти;
Попытка
Ждать Документ.ЗаписатьАсинх(Поток, "", ТипФайлаДокументаPDF.PDF);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
ОшибкаОперации = ОписаниеОшибки();
Попытка
Поток.Закрыть();
Исключение
ОшибкаОперации = ОшибкаОперации + " Закрытие своего выходного потока: " + ОписаниеОшибки();
КонецПопытки;
ВызватьИсключение ОшибкаОперации;
КонецПопытки;
Возврат Данные;
КонецФункции
&НаКлиенте
Процедура ПроверитьСвойОтветСертификата(Результат, Сертификат)
Если ТипЗнч(Результат) <> Тип("СертификатКриптографии")
Или Base64Строка(Результат.Отпечаток) <> Base64Строка(Сертификат.Отпечаток) Тогда
ВызватьИсключение "Await должен вернуть включённый сертификат собственного субъекта";
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСвоиБайтыНаСервере()
Возврат УчебнаяАсинхроннаяПодписьPDF85.ПолучитьСвоиБайтыPDF();
КонецФункции
&НаКлиенте
Асинх Процедура Выполнить(Команда)
Если Занято Тогда
ВызватьИсключение "Дождитесь завершения своей текущей операции";
КонецЕсли;
Система = Новый СистемнаяИнформация;
Если (Система.ТипПлатформы <> ТипПлатформы.Windows_x86 И Система.ТипПлатформы <> ТипПлатформы.Windows_x86_64) Тогда
ВызватьИсключение "Нужен собственный тонкий Windows-клиент8.5.1.1343";
КонецЕсли;
Если Не ПодтверждаюСвойСтенд Тогда
ВызватьИсключение "Подтвердите только использование своего отдельного ключевого стенда";
КонецЕсли;
Метка = МеткаСертификата85;
ОтпечатокHex = ОтпечатокHex85;
UUID = Новый УникальныйИдентификатор(Метка);
Если Строка(UUID) <> Метка Тогда
ВызватьИсключение "Скопируйте фактическую метку собственного учебного сертификата";
КонецЕсли;
Занято = Истина;
Отчёт = "Собственная операция ещё не завершена";
Попытка
ДанныеPDF = ПолучитьСвоиБайтыНаСервере();
Документ = Ждать ПрочитатьСвоиБайтыАсинх(ДанныеPDF);
Менеджер = ПодготовитьСвойМенеджер();
Сертификат = НайтиСвойСертификат(Менеджер, Метка, ОтпечатокHex);
ДоПодписания = Ждать Документ.ПолучитьОписанияПодписейАсинх(Менеджер);
Если ТипЗнч(ДоПодписания) <> Тип("Массив") Или ДоПодписания.Количество() <> 0 Тогда
ВызватьИсключение "Собственный исходный PDF не должен содержать прежних подписей";
КонецЕсли;
Описание = ПодготовитьСвоюПодпись(Документ, Сертификат, Метка);
Штамп = Новый ТабличныйДокумент;
Штамп.Область(1, 1).Текст = "УЧЕБНЫЙ АСИНХРОННЫЙ САМОПОДПИСАННЫЙ ОБРАЗЕЦ";
Ждать Документ.ДобавитьПодписьАсинх(Менеджер, Описание, Штамп, Истина);
ПодписанныеБайты = Ждать ЗаписатьСвоиБайтыАсинх(Документ);
Если ПодписанныеБайты.Размер() = 0 Тогда
ВызватьИсключение "Не получены собственные подписанные PDF-байты";
КонецЕсли;
Копия = Ждать ПрочитатьСвоиБайтыАсинх(ПодписанныеБайты);
Описания = Ждать Копия.ПолучитьОписанияПодписейАсинх(Менеджер);
Если ТипЗнч(Описания) <> Тип("Массив") Или Описания.Количество() <> 1 Тогда
ВызватьИсключение "Из новых PDF-байтов должно вернуться одно описание собственной подписи";
КонецЕсли;
Подпись = Описания[0];
Если ТипЗнч(Подпись) <> Тип("ОписаниеПодписиPDF") Или Подпись.Имя <> Описание.Имя Тогда
ВызватьИсключение "Await описаний не вернул именно собственную добавленную подпись";
КонецЕсли;
ПроверитьСвойОтветСертификата(Подпись.Сертификат, Сертификат);
ДатаПодписи = Подпись.Дата;
Если ТипЗнч(ДатаПодписи) <> Тип("Дата") Или ДатаПодписи = Дата(1, 1, 1) Тогда
ВызватьИсключение "В своём описании нет заполненной native-даты; подстановка текущей даты запрещена";
КонецЕсли;
ПроверенныйСертификат = Ждать Копия.ПроверитьПодписьАсинх(Описание.Имя, Менеджер);
ПроверитьСвойОтветСертификата(ПроверенныйСертификат, Сертификат);
ВсеСертификаты = Ждать Копия.ПроверитьПодписиАсинх(Менеджер);
Если ТипЗнч(ВсеСертификаты) <> Тип("Массив") Или ВсеСертификаты.Количество() <> 1 Тогда
ВызватьИсключение "Await всех подписей должен вернуть один включённый собственный сертификат";
КонецЕсли;
ПроверитьСвойОтветСертификата(ВсеСертификаты[0], Сертификат);
Отчёт = "Все await завершены: собственная подпись и сертификаты проверены. Native-дата: " + Строка(ДатаПодписи)
+ ". Это не доверенная TSA-дата и не правовая оценка";
Исключение
Занято = Ложь;
Отчёт = "Свой асинхронный опыт не завершён: " + ОписаниеОшибки();
ВызватьИсключение Отчёт;
КонецПопытки;
Занято = Ложь;
КонецПроцедурыУчебнаяАсинхроннаяПодписьPDF85
Конфигуратор → Общие модули → УчебнаяАсинхроннаяПодписьPDF85 → Модуль
Полный серверный общий модуль: защита своего пустого стенда и создание только своих unsigned PDF-байтов в памяти. Не выполнялся.
Процедура ПроверитьСвойПустойСтенд()
Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
КонецЕсли;
Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
КонецЕсли;
Источники = Новый Массив;
Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
Для Каждого Источник Из Источники Цикл
Расширения = РасширенияКонфигурации.Получить(, Источник);
Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
ВызватьИсключение "Native список расширений должен иметь тип Массив";
КонецЕсли;
Если Расширения.Количество() <> 0 Тогда
ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
КонецЕсли;
КонецЦикла;
Если ТранзакцияАктивна() Тогда
ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
КонецЕсли;
КонецПроцедуры
Функция СоздатьСобственныеБайтыPDF()
Таблица = Новый ТабличныйДокумент;
Таблица.КодЯзыка = "ru";
Таблица.Область(1, 1).Текст = "СОБСТВЕННЫЙ УЧЕБНЫЙ ОБРАЗЕЦ";
Таблица.Область(2, 1).Текст = "Книга";
Таблица.Область(2, 2).Текст = "3";
Таблица.Область(2, 3).Текст = "250";
Таблица.Область(2, 4).Текст = "750";
Таблица.Область(1, 1, 2, 4).ЦветФона = Новый Цвет(255, 255, 210);
Таблица.Область(, 1, , 1).ШиринаКолонки = 45;
Поток = Новый ПотокВПамяти;
Попытка
Таблица.Записать(Поток, ТипФайлаТабличногоДокумента.PDF);
Данные = Поток.ЗакрытьИПолучитьДвоичныеДанные();
Исключение
Поток.Закрыть();
ВызватьИсключение;
КонецПопытки;
Возврат Данные;
КонецФункции
Функция ПолучитьСвоиБайтыPDF() Экспорт
ПроверитьСвойПустойСтенд();
Возврат СоздатьСобственныеБайтыPDF();
КонецФункцииРазбор по шагам
Клиент проверяет точное имя своей конфигурации, версию/Windows и подтверждение учебного стенда. Supporting-серверный модуль отдельно проверяет отсутствие рабочих объектов/расширений ДО экспорта собственных байтов. Серверная защита не скопирована в контекст тонкого клиента.
Свои байты получают полный реальный источник: собственная таблица Книга/3/250/750 → PDF в ПотокВПамяти на сервере → ДвоичныеДанные в свою форму. Клиент открывает собственный поток чтения и ждёт ПрочитатьАсинх до его закрытия.
Полные клиентские функции проверяют настоящий CryptoAPI Type24/SHA256 и собственный CurrentUser-сертификат по20байтам отпечатка и CN с UUID. ВключатьСертификатСубъекта задан явно, TSA-массив пуст. Файл/ключ с неизвестным источником не принимается.
До подписи Ждать ПолучитьОписанияПодписейАсинх возвращает настоящий Массив: требуется0. Promise без Ждать не имеет готового количества; нельзя сравнить сам Promise с пустым массивом.
Собственное описание проверяет реальную первую страницу и поля, получает свой сертификат/имя и прямоугольник. Ждать ДобавитьПодписьАсинх ждёт завершения создания подписи; никакого нового готового ДокументPDF этот результат не обещает.
Новый выходной ПотокВПамяти передаётся ЗаписатьАсинх с ЯВНЫМ ПУСТЫМ паролем и PDF-форматом. Native-контракт запрещает запись подписанного PDF с непустым паролем. Только после Ждать поток закрывается с получением новых байтов.
Подписанные байты читаются новым независимым ДокументPDF через второй awaited ПрочитатьАсинх. ПолучитьОписанияПодписейАсинх у Копия должен вернуть1 ДО индекса0; сверяются реальный тип, имя, свой отпечаток и readonly native-дата.
Ждать ПроверитьПодписьАсинх(Имя, Менеджер) возвращает СертификатКриптографии. В отличие от синхронного overload, третьего выходного параметра нет. Полученный сертификат проверяется по типу/своему отпечатку, не по непустому представлению.
Ждать ПроверитьПодписиАсинх(Менеджер) возвращает Массив сертификатов. В отличие от синхронного overload, второго выходного параметра нет. Проверяем Array/количество1 ДО индекса0 и тот же фактический отпечаток.
Потоки чтения закрываются после завершившегося await; при исключении ошибка закрытия добавляется к исходной ошибке, не превращает её в успех. Выходной поток закрывается с байтами при успехе и отдельно на ошибке. Флаг Занято восстанавливается независимо от итогового статуса.
Строка успеха появляется только ПОСЛЕ всех awaited операций и сравнений. Ошибка любого этапа формирует отчёт об ошибке и повторно выбрасывается. CA/отзыв/правовая сила и доверенная TSA-дата не обещаются.
Как проверить результат
Будущий результат на полностью подготовленном своём тонком клиенте: исходных подписей0, из новых байтов возвращается1; фактическое имя/сертификат/дата совпадают с собственным источником, оба awaited метода проверки возвращают ожидаемые реальные типы. Занято в конце Ложь.
Будущий отрицательный контроль: у ПроверитьПодписьАсинх временно передайте Описание.Имя + "_отсутствует". Promise должен завершиться ошибкой, отчёт успеха не появиться, Занято вернуться в Ложь. Не заменяйте имя другой подписью автоматически.
Будущий контроль результатов: после Ждать проверки всех подписей временно замените ВсеСертификаты на Новый Массив. Проверка количества должна отказать ДО индекса0, несмотря на ранее завершённые операции.
Будущий контроль источника: перед чтением Копия подайте ДанныеPDF вместо ПодписанныеБайты. Массив описаний будет0 и должен быть отвергнут. Верните новые подписанные байты после опыта.
Будущий контроль повторного старта: вызовите собственную кнопку повторно, пока Занято=Истина. Второй запуск должен отказать до открытия потока/использования ключа. Не закрывайте форму для имитации отмены.
runtimeVerifiedScenarios=0: BSL, тонкий клиент, ключи, подпись, PDF-потоки и GUI здесь не запускались. Успех статических проверок не удостоверяет завершение Promise на конкретном провайдере.
Ожидаемый результат
Все awaited PDF-операции завершены, из новых своих подписанных байтов получены и проверены реальные описание, дата и сертификаты; флаг занятости очищен, доверие/правовая сила не заявлены
На что обратить внимание
Это отдельный урок со своим закрытым ключом, не продолжение опыта с публичным DER Syntax Guide Training Only. Публичный DER из предыдущего урока не может заменить этот ключ.
Создание учебного ключа — осознанное будущее изменение ТОЛЬКО своего изолированного профиля. Оно не выполнялось инструментами этого чата. NonExportable не означает, что ключ исчезнет после опыта или что он доверенный.
Чтение описания/даты — не эквивалент ПроверитьПодпись, проверки CA/отзыва или доверенной TSA-метки. Никакого правового вывода по self-signed образцу не делается.
Текст штампа — визуальное представление, не сама криптографическая подпись. Не обещается, что все PDF-просмотрщики доверяют self-signed сертификату или одинаково показывают штамп.
Ключ принадлежит текущему учебному Windows-клиенту. Сервер создаёт только свои PDF-байты и ключ не использует; ошибка источника не разрешает переключиться на чужой профиль или область ДанныеКомпьютера.
Новый ОписаниеПодписиPDF — настройки до подписи, не источник фактической readonly-даты. Её читаем только из awaited описаний новых подписанных PDF-байтов.
Четыре PDF Async-метода доступны клиенту, не серверу. Синхронные методы подписания/чтения/проверки не вставлены вместо Async в основном модуле формы.
Promise надо дождаться внутри Асинх Процедура/Функция. ПолучитьОписанияПодписейАсинх возвращает Array после ожидания, ПроверитьПодписьАсинх — Certificate, ПроверитьПодписиАсинх — Array; это разные контракты.
Асинхронное ожидание — не фоновая серверная работа и не гарантия, что синхронная инициализация криптографии не блокирует интерфейс. Разрешённый синхронный режим указан явно; браузерные расширения не устанавливаются.
Пустой пароль записи обязателен для этого подписанного образца. Непустой пароль должен вызвать native-ошибку; её нельзя скрыть и вернуть старые байты как новый результат.
Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.