Управление подключением DSS / Модуль менеджера

файл
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2024, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// Следующие процедуры и функции предназначены для интеграции с 1С:Библиотека электронных документов.

#Область ОбработкаЗаявления

#Область ФоновыеЗадания

// Обращается к сервису для получения реестра зарегистрированных серверов облачной подписи
//
// Параметры:
//  ПараметрыФункции 					- Структура:
//    * ВнутреннийИдентификатор 		- Строка - необязательный, используется для фильтрации списка
//  АдресРезультата						- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Массив из Структура - каждая строка содержит поля:
//    * Ссылка 						- СправочникСсылка.УчетныеЗаписиDSS
//    * Наименование					- Строка
//    * АдресСервера					- Строка
//    * АдресЛичногоКабинета			- Строка
//    * СервисИдентификации			- Строка
//    * СервисПодписи					- Строка
//    * СервисПроверки				- Строка
//    * ВнутреннийИдентификатор		- Строка
//    * ИдентификаторЦИ				- Строка
//    * ИдентификаторСЭП				- Строка
//    * ШаблонПодтверждения			- Строка
//    * ТаймАут						- Число
//    * ВерсияАПИ						- Строка
//    * Комментарий					- Строка
//    * Используется					- Булево
//    * ОграничениеАвторизации		- Строка
//    * ПользовательШифрования		- Строка
//    * ПарольПользовательШифрования 	- Строка
//
Функция ОбменССерверомСписокСерверовОблачнойПодписи(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Массив;
	ВнутреннийИдентификатор = СвойствоСтруктуры(ПараметрыФункции, "ВнутреннийИдентификатор", "");
	
	ПараметрыПодключения = ПараметрыПодключенияСервисов("СписокСерверовDSS");
	
	ПараметрыЗапроса = Новый Структура;
	Если ЗначениеЗаполнено(ВнутреннийИдентификатор) Тогда
		ПараметрыЗапроса.Вставить("id", ВнутреннийИдентификатор);
	КонецЕсли;
	
	ОтветСервиса = ВыполнитьЗапросREST(ПараметрыПодключения, ПараметрыЗапроса);
	Если ОтветСервиса.Выполнено Тогда
		СоответствиеТипов = СпособыАвторизацииОблачнойПодписи();

		Для Каждого ТекущийЭлемент Из ОтветСервиса.Результат Цикл
			ОписаниеСервиса = ПолучитьОписаниеСервисаОблачнойПодписи();
			
			ОписаниеСервиса.Наименование = СвойствоСтруктуры(ТекущийЭлемент, "srvUri", "");
			ОписаниеСервиса.АдресСервера = СвойствоСтруктуры(ТекущийЭлемент, "srvUri", "");
			ОписаниеСервиса.СервисПодписи = СвойствоСтруктуры(ТекущийЭлемент, "sgnSrv", "");
			ОписаниеСервиса.СервисИдентификации = СвойствоСтруктуры(ТекущийЭлемент, "stsSrv", "");
			ОписаниеСервиса.СервисПроверки = СвойствоСтруктуры(ТекущийЭлемент, "verSrv", "");
			ОписаниеСервиса.ИдентификаторЦИ = СвойствоСтруктуры(ТекущийЭлемент, "stsId", "");
			ОписаниеСервиса.ИдентификаторСЭП = СвойствоСтруктуры(ТекущийЭлемент, "sgnId", "");
			
			ОписаниеСервиса.Используется = СвойствоСтруктуры(ТекущийЭлемент, "isUsed", Истина);
			ОписаниеСервиса.ТаймАут = СвойствоСтруктуры(ТекущийЭлемент, "timeout", 120);
			ОписаниеСервиса.ВерсияАПИ = СвойствоСтруктуры(ТекущийЭлемент, "apiVer", "");
			ОписаниеСервиса.АдресЛичногоКабинета = СвойствоСтруктуры(ТекущийЭлемент, "accUri", "");
			ОписаниеСервиса.ВнутреннийИдентификатор = СвойствоСтруктуры(ТекущийЭлемент, "prvId", "");
			
			ОписаниеСервиса.ПользовательШифрования = СвойствоСтруктуры(ТекущийЭлемент, "pubUser", "");
			ОписаниеСервиса.ПарольПользовательШифрования = СвойствоСтруктуры(ТекущийЭлемент, "pubUserPassword", "");
			
			ВариантАутентификации = СвойствоСтруктуры(ТекущийЭлемент, "authMeth", 3);
			СпособАвторизации = СвойствоСтруктуры(ТекущийЭлемент, "cfrmMeth", 9);
			
			Если ВариантАутентификации = 3 И СпособАвторизации = 9 Тогда
				ВариантАутентификации = -2;
			КонецЕсли;
			
			ОграничениеАвторизации = Новый Массив;
			ОграничениеАвторизации.Добавить(СоответствиеТипов[ВариантАутентификации]);
			ОграничениеАвторизации.Добавить(СоответствиеТипов[СпособАвторизации]);
			
			ОписаниеСервиса.ОграничениеАвторизации = СтрСоединить(ОграничениеАвторизации, ",");
			
			Результат.Добавить(ОписаниеСервиса);
			
		КонецЦикла;
		
	КонецЕсли;	
	
	Если АдресРезультата <> Неопределено Тогда
		ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Обращается к сервису для проверки существования указанного логина и получения реестра серверов
//
// Параметры:
//  ПараметрыФункции 				- Структура:
//    * Логин					- Строка
//    * ВнутреннийИдентификатор 	- Строка - необязательный
//  АдресРезультата					- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Логин 					- Строка
//    * Сервисы					- Массив из см. ОбменССерверомСписокСерверовОблачнойПодписи
//
Функция ОбменССерверомПроверитьПодключение(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Логин = СвойствоСтруктуры(ПараметрыФункции, "Логин", "");
	ВнутреннийИдентификатор = СвойствоСтруктуры(ПараметрыФункции, "ВнутреннийИдентификатор", "");
	
	ВсеСервисы = ОбменССерверомСписокСерверовОблачнойПодписи(Неопределено);
	
	Результат = Новый Структура;
	Результат.Вставить("Логин", Логин);
	Результат.Вставить("Сервисы", ВсеСервисы);
	Результат.Вставить("ЛогинОбнаружен", Ложь);
	
	Если НЕ ЗначениеЗаполнено(ВнутреннийИдентификатор) И ВсеСервисы.Количество() > 1 Тогда
		ВнутреннийИдентификатор = ВсеСервисы[0].АдресСервера;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ВнутреннийИдентификатор) И ЗначениеЗаполнено(Логин) Тогда
		ПараметрыВызова = Новый Структура;
		ПараметрыВызова.Вставить("ВнутреннийИдентификатор", ВнутреннийИдентификатор);
		ПараметрыВызова.Вставить("Логин", Логин);
		РезультатПроверки = ОбменССерверомПроверитьЛогин(ПараметрыВызова);
		Если РезультатПроверки.Пройден = Ложь Тогда
			Результат.Вставить("Логин", РезультатПроверки.Варианты);
			Результат.Вставить("ЛогинОбнаружен", Истина);
		КонецЕсли;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, НСтр("ru = 'Проверить подключение'"));
	
КонецФункции

// Вызывает сервис проверки логина учетной записи.
//
// Параметры:
//  ПараметрыФункции 					- Структура:
//    * ВнутреннийИдентификатор 		- Строка - идентификатор сервера
//    * Логин							- Строка
//  АдресРезультата						- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено 					- Булево
//    * Варианты						- Строка
//    * Ошибка						- Строка
//
Функция ОбменССерверомПроверитьЛогин(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Пройден", Неопределено);
	Результат.Вставить("Варианты", "");
	Результат.Вставить("Ошибка", "");
	
	Логин = ПараметрыФункции.Логин;
	ВнутреннийИдентификатор = ПараметрыФункции.ВнутреннийИдентификатор;
	
	ПараметрыПодключения = ПараметрыПодключенияСервисов("ПроверитьЛогинDSS");
	
	ПараметрыЗапроса = Новый Структура;
	ПараметрыЗапроса.Вставить("login", Логин);
	Если ЗначениеЗаполнено(ВнутреннийИдентификатор) Тогда
		ПараметрыЗапроса.Вставить("prvId", ВнутреннийИдентификатор);
	КонецЕсли;
	
	ОтветСервиса = ВыполнитьЗапросREST(ПараметрыПодключения, ПараметрыЗапроса);
	Если ОтветСервиса.Выполнено Тогда
		Результат.Пройден = СвойствоСтруктуры(ОтветСервиса.Результат, "isFree", Ложь);
		Результат.Варианты = СвойствоСтруктуры(ОтветСервиса.Результат, "Login", "");
	Иначе
		Результат.Ошибка = ОтветСервиса.Ошибка;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, НСтр("ru = 'Проверить логин'"));
	
КонецФункции

// Вызывает сервис активирования логина учетной записи.
// В случае успеха в настройках сервера облачной подписи включается аутентификация по паролю, отключается
// подтверждение всех операций.
//
// Параметры:
//  ПараметрыФункции 			- Структура:
//    * ИдентификаторСубъекта - Строка - идентификатор отправленного заявления
//    * ИдентификаторПодписи	- Строка - подписываемые данные
//    * ДанныеПодписи         - ДвоичныеДанные - данные подписи идентификатора подписи
//  АдресРезультата				- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено 			- Булево
//    * Ошибка				- Строка
//
Функция ОбменССерверомАктивироватьУчетнуюЗапись(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Ложь);
	Результат.Вставить("Ошибка", "");
	
	ИдентификаторСубъекта = ПараметрыФункции.ИдентификаторСубъекта;
	ПодписьПароля = ПараметрыФункции.ПодписьПароля;
	ДанныеПодписи = ПараметрыФункции.ДанныеПодписи;
	
	Заголовки = Новый Соответствие;
	Заголовки.Вставить("Content-Type", "application/json");
	
	ПараметрыПодключения = ПараметрыПодключенияСервисов("АктивироватьПароль");
	ПараметрыПодключения.ТочкаПодключения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
												ПараметрыПодключения.ТочкаПодключения, ИдентификаторСубъекта, ПодписьПароля);
	
	ОтветСервиса = ВыполнитьЗапросREST(ПараметрыПодключения, 
		ОбщегоНазначения.ЗначениеВJSON(ПолучитьBase64СтрокуИзДвоичныхДанных(ДанныеПодписи)), "POST", Заголовки);
	
	Если ОтветСервиса.Выполнено Тогда
		Если СвойствоСтруктуры(ОтветСервиса.Результат, "code", "-1") <> "0" Тогда
			Результат.Ошибка = НСтр("ru = 'Ошибка активирования учетной записи'");
		Иначе
			Результат.Выполнено = Истина;
		КонецЕсли;
	Иначе
		Результат.Ошибка = ОтветСервиса.Ошибка;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, НСтр("ru = 'Активировать учетную запись'"));
	
КонецФункции

// Вызывает сервис активирования ключа для мобильного приложения (QR-code).
//
// Параметры:
//  ПараметрыФункции 			- Структура:
//    * ИдентификаторСубъекта - Строка
//    * ПодписьПриложения		- ДвоичныеДанные
//  АдресРезультата				- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено				- Булево
//    * Результат				- Булево - результат активирования
//    * Ошибка				- Строка
//
Функция ОбменССерверомАктивироватьКлючПриложенияУчетнойЗаписи(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Истина);
	Результат.Вставить("Результат", Ложь);
	Результат.Вставить("Ошибка", "");
	
	ПодписьПриложения = ПараметрыФункции.ПодписьПриложения;
	ИдентификаторСубъекта = ПараметрыФункции.ИдентификаторСубъекта;
	
	ПараметрыПодключения = ПараметрыПодключенияСервисов("АктивироватьКлючМобильногоПриложения");
	ПараметрыПодключения.АдресЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
											ПараметрыПодключения.АдресЗапроса, ИдентификаторСубъекта, ПодписьПриложения);
	
	ОтветСервиса = ВыполнитьЗапросREST(ПараметрыПодключения, Неопределено);
	
	Если ОтветСервиса.Выполнено Тогда
		Если СвойствоСтруктуры(ОтветСервиса.Результат, "code", "-1") = "0" Тогда
			Результат.Результат = Истина;
		КонецЕсли;
	Иначе
		Результат.Ошибка = ОтветСервиса.Ошибка;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, НСтр("ru = 'Активировать ключ мобильного приложения'"));
	
КонецФункции

// Вызывает сервис отправки кода активация для ключа мобильного приложения.
//
// Параметры:
//  ПараметрыФункции 					- Структура:
//    * ПодписьКодаАктивацииПриложения- Строка
//    * ИдентификаторСубъекта			- Строка 
//  АдресРезультата						- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено						- Булево
//    * Результат						- Булево - результат активирования
//    * Ошибка						- Строка
//
Функция ОбменССерверомОтправитьКодАктивацииКлюча(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Ложь);
	
	ПараметрыПодключения = ПараметрыПодключенияСервисов("ОтправитьКодАктивацииКлюча");
	ПодписьКода = ПараметрыФункции.ПодписьКодаАктивацииПриложения;
	ИдентификаторСубъекта = ПараметрыФункции.ИдентификаторСубъекта;
	
	ПараметрыПодключения.АдресЗапроса = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
											ПараметрыПодключения.АдресЗапроса, ИдентификаторСубъекта, ПодписьКода);
	
	ОтветСервиса = ВыполнитьЗапросREST(ПараметрыПодключения, Неопределено);
	Если ОтветСервиса.Выполнено Тогда
		Если СвойствоСтруктуры(ОтветСервиса.Результат, "code", "-1") = "0" Тогда
			Результат.Выполнено = Истина;
		КонецЕсли;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, НСтр("ru = 'Отправка кода активации мобильного приложения'"));
	
КонецФункции

// Отправляет заявление на изменение параметров подключения облачной подписи на портал УЦ.
//
// Параметры:
//  ПараметрыФункции 					- Структура:
//    * Заявление						- Строка - содержимое заявления в формате XML
//    * ПодписьЗаявления				- ДвоичныеДанные, Неопределено - ЭП сформированная для заявления
//    * ИдентификаторДокументооборота - Строка - идентификатор отправляемого заявления
//    * ТикетПользователя				- Строка - предварительно полученный тикет пользователя из сервиса Интернет-поддержки
//  АдресРезультата						- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено						- Булево
//    * Ошибка						- Строка
//    * ИдентификаторДокументооборота	- Строка
//    * ДатаОтправки					- Дата
//
Функция ОтправитьЗаявлениеНаПортал(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	ВидОперации = НСтр("ru = 'Отправить заявление на портал'");
	Заявление = ПараметрыФункции.Заявление;
	ПодписьЗаявления = ПараметрыФункции.ПодписьЗаявления;
	ИдентификаторДокументооборота = ПараметрыФункции.ИдентификаторДокументооборота;
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Ложь);
	Результат.Вставить("Ошибка", "");
	Результат.Вставить("ИдентификаторДокументооборота", ИдентификаторДокументооборота);
	Результат.Вставить("ДатаОтправки", Неопределено);
	
	ОписаниеОшибки = "";
	ШаблонОписанияОшибки = НСтр("ru = 'Не удалось отправить заявление по причине:
		|%1'");
	
	ВсеАдреса = АдресаСервисовОбработкиЗаявления();
	
	Попытка
		ВебСервис = ВебСервисУЦ(ВсеАдреса.ВебСервис, "http://regservice.keydisk.ru/", "RegService");
	Исключение
		
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
		
	КонецПопытки;
	
	ЭтоПовторнаяОтправкаПакета = Истина;
	Если Не ЗначениеЗаполнено(Результат.ИдентификаторДокументооборота) Тогда
		ЭтоПовторнаяОтправкаПакета = Ложь;
		Результат.ИдентификаторДокументооборота = НовыйСжатыйУникальныйИдентификатор();
	КонецЕсли;
	
	ПакетЗаявления = ПакетЗаявления(Заявление, Результат.ИдентификаторДокументооборота, ПодписьЗаявления);
	
	Попытка
		ОтветСервиса = ВебСервис.SendPacket(ПакетЗаявления);
	Исключение
		
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
		
	КонецПопытки;
	
	Если Не ЗначениеЗаполнено(ОтветСервиса) Тогда
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			НСтр("ru = 'Сервер вернул пустой ответ.'"));
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	КонецЕсли;
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(ОтветСервиса);
	
	ПостроительDOM = Новый ПостроительDOM();
	ПостроительDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	
	ЧтениеXML.Закрыть();
	
	УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("code");
	КодРезультата = УзелDOM[0].ТекстовоеСодержимое;
	Если КодРезультата = "0" Тогда
		Результат.ДатаОтправки = ТекущаяДатаСеанса();
		Результат.Выполнено = Истина;
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	ИначеЕсли КодРезультата = "60" // Документооборот уже зарегистрирован.
		И ЭтоПовторнаяОтправкаПакета Тогда
		Результат.ДатаОтправки = ТекущаяДатаСеанса();
		Результат.Выполнено = Истина;
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	КонецЕсли;
	
	Результат.ИдентификаторДокументооборота = "";
	
	УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("errorMessage");
	Если УзелDOM.Количество() > 0 Тогда
		ОписаниеОшибки = УзелDOM[0].ТекстовоеСодержимое;
	КонецЕсли;
	
	Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
		ОписаниеОшибки);
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	
КонецФункции

// Получает тикет пользователя Интернет-поддержки
//
// Параметры:
//  ПараметрыФункции 					- Структура
//  АдресРезультата						- Строка - в случае необходимости содержит адрес временного хранилища куда помещается результат
//
// Возвращаемое значение:
//  - Строка 
//  - Неопределено
//
Функция ПолучитьТикетИнтернетПоддержкиПользователя(ПараметрыФункции, АдресРезультата = Неопределено) Экспорт
	
	Результат = Новый Структура();
	Результат.Вставить("Выполнено", Ложь);
	Результат.Вставить("Ошибка", "");
	Результат.Вставить("Тикет", Неопределено);
	
	ВидОперации = НСтр("ru = 'Получить тикет'");
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей") Тогда
		Результат.Ошибка = НСтр("ru = 'Невозможно подключиться к порталу интернет-поддержки по причине:
			|Библиотека интернет-поддержки пользователей не внедрена в конфигурацию.'");
		Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	КонецЕсли;
	
	Результат.Вставить("Выполнено", Истина);
	
	МодульИнтернетПоддержкаПользователей = ОбщегоНазначения.ОбщийМодуль("ИнтернетПоддержкаПользователей");
	УстановитьПривилегированныйРежим(Истина);
	ОтветСервиса = МодульИнтернетПоддержкаПользователей.ТикетАутентификацииНаПорталеПоддержки("http://regservice.1c.ru");
	УстановитьПривилегированныйРежим(Ложь);
	
	Если ЗначениеЗаполнено(ОтветСервиса.КодОшибки) Тогда
		Если ОтветСервиса.КодОшибки = "НеверныйЛогинИлиПароль" Тогда
			Результат.Тикет = "";
		КонецЕсли;
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось подключиться к порталу интернет-поддержки по причине:
			|%1'"), ОтветСервиса.СообщениеОбОшибке);
	Иначе
		Результат.Тикет = ОтветСервиса.Тикет;
	КонецЕсли;
	
	Возврат ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации);
	
КонецФункции

#КонецОбласти

// Возвращает список реквизитов заявления необходимых для отправки в сервис регистрации
//
// Возвращаемое значение:
//  Структура
//
Функция СтруктураРеквизитовЗаявления() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ДатаЗаявления", ТекущаяДатаСеанса());
	Результат.Вставить("ИдентификаторЗаявления", "");
	Результат.Вставить("ИдентификаторАбонента", "");
	Результат.Вставить("СостояниеЗаявления", Перечисления.СостоянияЗаявленияУчетнойЗаписиDSS.НеПодготовлено);
	Результат.Вставить("ОтпечатокСертификата", "");
	Результат.Вставить("НомерТелефона", "");
	Результат.Вставить("НомерТелефонаXML", "");
	Результат.Вставить("НомерТелефонаПроверен", Ложь);
	Результат.Вставить("ЭлектроннаяПочта", "");
	Результат.Вставить("ЭлектроннаяПочтаПроверена", Ложь);
	Результат.Вставить("ИНН", "");
	Результат.Вставить("КПП", "");
	Результат.Вставить("СрокQRКода", '00010101');
	Результат.Вставить("Режим_СменаКонтактов", Ложь);
	Результат.Вставить("Режим_ПовторнаяОтправкаКлючМобильногоПриложения", Ложь);
	Результат.Вставить("Режим_ПовторнаяОтправкаКодаАктивации", Ложь);
	Результат.Вставить("Режим_СменаКлючаМобильногоПриложения", Ложь);
	Результат.Вставить("Режим_СменаПароля", Ложь);
	Результат.Вставить("Режим_ИзданиеСертификата", Ложь);
	Результат.Вставить("ТекстЗаявления", "");
	
	Возврат Результат;
	
КонецФункции

// Формирует структуру для поиска в файлах настроек необходимых разделов
//
// Параметры:
//   ТекущаяУчетнаяЗапись- СправочникСсылка.УчетныеЗаписиDSS
//  Сервер				- Строка
//  Логин				- Строка
//
// Возвращаемое значение:
//  Структура:
//    * Сервер		- Строка
//    * Логин			- Строка
//
Функция КлючПоискаУчетнойЗаписи(ТекущаяУчетнаяЗапись, Сервер = "", Логин = "") Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Сервер", Сервер);
	Результат.Вставить("Логин", Логин);
	
	Если ЗначениеЗаполнено(ТекущаяУчетнаяЗапись) Тогда
		ВсеЗаписи = СервисКриптографииDSS.ПолучитьВсеУчетныеЗаписи(ТекущаяУчетнаяЗапись);
		Если ВсеЗаписи.Количество() > 0 Тогда
			Результат.Сервер = ВсеЗаписи[0].ВнутреннийИдентификатор;
			Результат.Логин = ВсеЗаписи[0].Логин;
		КонецЕсли;
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

// Анализирует состояние блока конфиденциальной информации
//
// Параметры:
//  ШифрованныйБлок 			- Строка
//                  			- ДвоичныеДанные
//  КлючПоиска					- см. КлючПоискаУчетнойЗаписи
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено 			- Булево - Истина, если блок содержит корректные данные
//    * Пароль				- Строка
//    						- Неопределено
//    * КлючПриложения		- Строка
//    						- Неопределено
//    * НовыйКлючПриложения	- Строка
//    						- Неопределено
//    * ПодписьПриложения	- Строка
//    						- Неопределено
//	
Функция СлужебныеДанныеОблачнойПодписи(ШифрованныйБлок, КлючПоиска = Неопределено) Экспорт
	
	Успешно = Ложь;
	
	Если ЭтоАдресВременногоХранилища(ШифрованныйБлок) Тогда
		ДанныеБлока = ПолучитьИзВременногоХранилища(ШифрованныйБлок);
	Иначе
		ДанныеБлока = ШифрованныйБлок;
	КонецЕсли;
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Ложь);
	Результат.Вставить("Пароль", Неопределено);
	Результат.Вставить("НовыйКлючПриложения", Неопределено);
	Результат.Вставить("КлючПриложения", Неопределено);
	Результат.Вставить("ПодписьПриложения", Неопределено);
	Результат.Вставить("ПодписьКодаАктивации", Неопределено);
	Результат.Вставить("ПодписьПароля", Неопределено);
	
	Пароль = Неопределено;
	КлючПриложения = Неопределено;
	НовыйКлючПриложения = Неопределено;
	ПодписьПриложения = Неопределено;
	ПодписьПароля = Неопределено;
	ПодписьКодаАктивации = Неопределено;
	
	Попытка
		Текст = ПолучитьСтрокуИзДвоичныхДанных(ДанныеБлока, "windows-1251");
		Текст = "<?xml version=""1.0"" encoding=""windows-1251""?>" + Символы.ПС +
		"<корневойЭлемент>" + Текст + "</корневойЭлемент>"; 
	
		ЧтениеXML = Новый ЧтениеXML;
		ЧтениеXML.УстановитьСтроку(Текст);
		ПостроительDOM = Новый ПостроительDOM;
		ДокументDOM  = ПостроительDOM.Прочитать(ЧтениеXML);
		
		УзелDOM = ПолучитьЭлементУзлаDOM(ДокументDOM, "ОблачныйКлюч", Ложь);
		
		Для Счетчик = 0 По УзелDOM.Количество() - 1 Цикл
			
			Узел = УзелDOM[Счетчик];
			
			Сервер = ПолучитьАтрибутУзлаXML(Узел, "ИдентификаторСервиса", "");
			Логин = ПолучитьАтрибутУзлаXML(Узел, "ИмяПользователя", "");
			Пароль = ПолучитьАтрибутУзлаXML(Узел, "Пароль", "");
			НовыйКлючПриложения = ЗначениеУзлаXML(Узел, "QRКодНовый");
			КлючПриложения = ЗначениеУзлаXML(Узел, "QRКод");
			ПодписьПароля = ПолучитьАтрибутУзлаXML(Узел, "ПроверочныйКодАктивацииПароля", "");
			ПодписьКодаАктивации = ПолучитьАтрибутУзлаXML(Узел, "ПроверочныйКодПолученияКодаАктивации", "");
			ПодписьПриложения = ПолучитьАтрибутУзлаXML(Узел, "ПроверочныйКодАктивацииКлючаИПолученияКодаАктивации", "");
			
			Если ЗначениеЗаполнено(НовыйКлючПриложения) Тогда
				КлючПриложения = Base64Значение(НовыйКлючПриложения);
			КонецЕсли;
			
			Если ЗначениеЗаполнено(КлючПриложения) Тогда
				КлючПриложения = Base64Значение(КлючПриложения);
			КонецЕсли;
			
			Если КлючПоиска = Неопределено 
				ИЛИ (КлючПоиска.Сервер = Сервер
				И КлючПоиска.Логин = Логин) Тогда
				Успешно = Истина;
			КонецЕсли;	
			
		КонецЦикла;
		
	Исключение
		Успешно = Ложь;
		
	КонецПопытки;
	
	Результат.Выполнено = Успешно;
	Если Успешно Тогда
		Результат.Пароль = Пароль;
		Результат.НовыйКлючПриложения = КлючПриложения;
		Результат.КлючПриложения = КлючПриложения;
		Результат.ПодписьПриложения = ПодписьПриложения;
		Результат.ПодписьПароля = ПодписьПароля;
		Результат.ПодписьКодаАктивации = ПодписьКодаАктивации;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции	

// Создает или обновляет данные учетной записи облачной подписи
//
// Параметры:
//  ДанныеСервиса 		- СправочникСсылка.ЭкземплярыСервераDSS, Структура - если передана структура, 
//						то она должна соответствовать см. ПолучитьОписаниеСервисаОблачнойПодписи()
//  Логин				- Строка
//  РежимАутентификации - Строка
//  ОбновлятьДанные		- Булево - принудительно обновлять данные
//
// Возвращаемое значение:
//  СправочникСсылка.УчетныеЗаписиDSS
//
Функция СоздатьУчетнуюЗаписьОблачнойПодписи(ДанныеСервиса, Логин, РежимАутентификации = "", ОбновлятьДанные = Ложь) Экспорт
	
	КодЯзыка = ОбщегоНазначения.КодОсновногоЯзыка();
	Результат = Неопределено;
	СсылкаСервера = Неопределено;
	ТекстОшибки = НСтр("ru = 'Недостаточно данных для восстановления учетной записи DSS.'", КодЯзыка) + " " + Логин;
	ВидОперации = НСтр("ru = 'Обновление учетной записи'");
	
	Если ТипЗнч(ДанныеСервиса) = Тип("Структура") Тогда
		Если ЗначениеЗаполнено(ДанныеСервиса.ВнутреннийИдентификатор) Тогда
			ВсеСервисы = СервисКриптографииDSS.ПолучитьВсеСерверы(Новый Структура("ВнутреннийИдентификатор", ДанныеСервиса.ВнутреннийИдентификатор));
		Иначе
			ВсеСервисы = СервисКриптографииDSS.ПолучитьВсеСерверы(Новый Структура("АдресСервера", ДанныеСервиса.АдресСервера));
		КонецЕсли;
		
		Если ВсеСервисы.Количество() > 0 И НЕ ОбновлятьДанные Тогда
			СсылкаСервера = ВсеСервисы[0].Ссылка;
		Иначе	
			СсылкаСервера = СервисКриптографииDSS.ОбновитьДанныеСервераОблачнойПодписи(ДанныеСервиса);
		КонецЕсли;	
	Иначе
		СсылкаСервера = ДанныеСервиса;
	КонецЕсли;
	
	Если НЕ ЗначениеЗаполнено(СсылкаСервера) Тогда
		ПодготовитьРезультатВызова(ТекстОшибки, Неопределено, ВидОперации);
		Возврат Результат;
	КонецЕсли;
	
	// определим способы авторизации и аутентификации
	МассивСпособов = СервисКриптографииDSS.СписокПервичнойАвторизации(СсылкаСервера);
	Если ЗначениеЗаполнено(РежимАутентификации) Тогда
		ПервичнаяАутентификация = Перечисления.СпособыАвторизацииDSS[РежимАутентификации];
	ИначеЕсли МассивСпособов.Количество() = 0 Тогда
		ПервичнаяАутентификация = Перечисления.СпособыАвторизацииDSS.Первичный_УчетныеДанные;
	Иначе
		ПервичнаяАутентификация = МассивСпособов[0];
	КонецЕсли;	
	
	МассивСпособов = СервисКриптографииDSS.СписокВторичнойАвторизации(СсылкаСервера);
	Если МассивСпособов.Количество() = 0 Тогда
		ВторичнаяАвторизация = Перечисления.СпособыАвторизацииDSS.Вторичный_МобильноеПриложение;
	Иначе
		ВторичнаяАвторизация = МассивСпособов[0];
	КонецЕсли;	
	
	СтрокаПоиска = Новый Структура("Владелец, Логин", СсылкаСервера, Логин);
	УчетнаяЗаписьОблачнойПодписи = СервисКриптографииDSS.НайтиУчетнуюЗапись(СтрокаПоиска);
	
	Если НЕ ЗначениеЗаполнено(УчетнаяЗаписьОблачнойПодписи) ИЛИ ОбновлятьДанные Тогда
		ОписаниеУчетнойЗаписи = Новый Структура;
		ОписаниеУчетнойЗаписи.Вставить("Владелец", СсылкаСервера);
		ОписаниеУчетнойЗаписи.Вставить("Логин", Логин);
		ОписаниеУчетнойЗаписи.Вставить("ПервичнаяАутентификация", ПервичнаяАутентификация);
		ОписаниеУчетнойЗаписи.Вставить("ВторичнаяАвторизация", ВторичнаяАвторизация);
		ОписаниеУчетнойЗаписи.Вставить("Комментарий", НСтр("ru = 'Заполнено в режиме восстановления учетной записи.'", КодЯзыка));
		Результат = СервисКриптографииDSS.ОбновитьДанныеУчетнойЗаписиОблачнойПодписи(ОписаниеУчетнойЗаписи);
		
	Иначе
		Результат = УчетнаяЗаписьОблачнойПодписи;
		
	КонецЕсли;	
	
	Если НЕ ЗначениеЗаполнено(Результат) Тогда
		ПодготовитьРезультатВызова(ТекстОшибки, Неопределено, ВидОперации);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Формирует параметры для формирования запроса на сертификат
//
// Параметры:
//   УчетнаяЗаписьОблачнойПодписи    - СправочникСсылка.УчетныеЗаписиDSS
//  ПоляЗаявления 					- Соответствие из КлючИЗначение: 
//    * Ключ						- Строка - идентификатор OID
//    * Значение					- Строка
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено					- Булево - обязательное
//    * КриптоПровайдер			- Строка
//    * КриптоПровайдер_Тип		- Число
//    * КриптоПровайдер_Имя		- Строка
//    * ШаблонСертификата			- Строка - имя шаблона
//    * УдостоверяющийЦентр		- Строка - идентификатор УЦ
//    * ИмяСертификата			- Строка - формируется из обязательных полей
//    * ПоляАтрибутов				- Соответствие - перечисление всех полей запроса
//
Функция ПолучитьДанныеДляЗапросаНаСертификат(УчетнаяЗаписьОблачнойПодписи, ПоляЗаявления) Экспорт
	
	Результат = Новый Структура();
	Результат.Вставить("Выполнено", Ложь);
	
	СводныеДанные = СервисКриптографииDSS.ПолучитьИнформациюУдостоверяющихЦентров(УчетнаяЗаписьОблачнойПодписи);
	Если СводныеДанные.Заполнено Тогда
		
		ТекущийКриптоПровайдер = Неопределено;
		ТекущийШаблон = Неопределено;
		УдостоверяющийЦентр = Неопределено;
		ПоляАтрибутов = Неопределено;
		ИмяСертификата = "";
		
		Для Каждого СтрокаМассива Из СводныеДанные.Криптопровайдеры Цикл
			ТекущийКриптоПровайдер = СтрокаМассива;
			Если СтрНайти(СтрокаМассива.Описание, "2012") Тогда
				Прервать;
			КонецЕсли;	
		КонецЦикла;	
		
		Для Каждого СтрокаМассива Из СводныеДанные.УдостоверяющиеЦентры Цикл
			ПоляУЦ = СервисКриптографииDSS.ПолучитьРеестрПолейУдостоверяющегоЦентра(СтрокаМассива);
			НовыеПоля = Новый Соответствие;
			ВсеОбязательные = 0;
			ИмяСертификата = "";
			Для Каждого СтрокаПоля Из ПоляУЦ Цикл
				ВсеОбязательные = ВсеОбязательные + ?(СтрокаПоля.Обязательно, 1, 0);
				ЗначениеПоля = ПоляЗаявления[СтрокаПоля.OID];
				
				Если СтрокаПоля.Обязательно Тогда
					ИмяСертификата = ИмяСертификата + ?(ПустаяСтрока(ИмяСертификата), "", ",") + СтрокаПоля.Имя + "=" + ЗначениеПоля;
				КонецЕсли;	
				
				Если ЗначениеПоля <> Неопределено Тогда
					НовыеПоля.Вставить(СтрокаПоля.OID, ЗначениеПоля);
					ВсеОбязательные = ВсеОбязательные - ?(СтрокаПоля.Обязательно, 1, 0);
				КонецЕсли;
				
			КонецЦикла;
			
			Если ВсеОбязательные = 0 Тогда
				УдостоверяющийЦентр = СтрокаМассива;
				ПоляАтрибутов = НовыеПоля;
				Прервать;
			КонецЕсли;	

		КонецЦикла;
		
		Если УдостоверяющийЦентр <> Неопределено Тогда 
			ШаблоныУЦ = СервисКриптографииDSS.ПолучитьРеестрШаблоновУдостоверяющегоЦентра(УдостоверяющийЦентр);
			Для Каждого СтрокаШаблона Из ШаблоныУЦ Цикл
				ТекущийШаблон = СтрокаШаблона.Шаблон;
				Если СтрНайти(СтрокаШаблона.Наименование, "2012") > 0 Тогда
					Прервать;
				КонецЕсли;	
			КонецЦикла;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ТекущийКриптоПровайдер) Тогда
			Результат.Вставить("КриптоПровайдер", ТекущийКриптоПровайдер.Идентификатор);
			Результат.Вставить("КриптоПровайдер_Тип", ТекущийКриптоПровайдер.Тип);
			Результат.Вставить("КриптоПровайдер_Имя", ТекущийКриптоПровайдер.Имя);
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ТекущийШаблон) Тогда
			Результат.Вставить("ШаблонСертификата", ТекущийШаблон);
		КонецЕсли;
		
		Если УдостоверяющийЦентр <> Неопределено Тогда 
			Результат.Вставить("УдостоверяющийЦентр", УдостоверяющийЦентр.Идентификатор);
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ИмяСертификата) Тогда
			ИмяСертификата = СтрЗаменить(ИмяСертификата, """", "");
			Результат.Вставить("ИмяСертификата", ИмяСертификата);
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ПоляАтрибутов) Тогда
			Результат.Вставить("ПоляАтрибутов", ПоляАтрибутов);
		КонецЕсли;
		
	КонецЕсли;	
	
	Если Результат.Количество() = 8 Тогда
		Результат.Выполнено = Истина;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Обновляет, создает элементы справочника на основании полученных данных для автоматических настроек
//
// Параметры:
//  ДокументDOM 						- ДокументDOM
//  КлючПоиска							- см. КлючПоискаУчетнойЗаписи
//  ОбновлятьДанные 					- Булево - принудительное обновление
//
// Возвращаемое значение:
//  Неопределено, Структура - в случае структуры содержит поля:
//    * Логин							- Строка
//    * ТелефонМобильный				- Строка
//    * ЭлектроннаяПочта				- Строка
//    * Отпечаток						- Строка
//    * ВнутреннийИдентификатор		- Строка
//    * РежимАутентификации           - Строка
//    * Сервер						- Структура - список полей описан в ПолучитьОписаниеСервисаОблачнойПодписи
//    * УчетнаяЗаписьОблачнойПодписи  - СправочникСсылка.УчетныеЗаписиDSS
//
Функция ОбновитьДанныеОблачнойПодписиВУчетнойЗаписи(ДокументDOM, КлючПоиска = Неопределено, ОбновлятьДанные = Истина) Экспорт
	
	Результат = Неопределено;
	УчетнаяЗаписьОблачнойПодписи = Неопределено;
	
	УзелDOM = ПолучитьЭлементУзлаDOM(ДокументDOM, "ВладелецЭЦП", Ложь);
	НашлиУзел = Ложь;
	
	Для Счетчик = 0 По УзелDOM.Количество() - 1 Цикл
		
		Узел = УзелDOM[Счетчик];
		Отпечаток = НРег(ЗначениеУзлаXML(Узел, "Отпечаток"));
		УзелDSS = ПолучитьЭлементУзлаDOM(Узел, "СведенияОПользователеDSS", Истина);
		СерверDSS = ПолучитьЭлементУзлаDOM(Узел, "СерверDSS");
		
		Сервер = ПолучитьАтрибутУзлаXML(УзелDSS, "ИдентификаторСервиса", "");
		Логин = ПолучитьАтрибутУзлаXML(УзелDSS, "ИмяПользователя", "");
					
		Если КлючПоиска = Неопределено 
			ИЛИ (КлючПоиска.Сервер = Сервер
			И КлючПоиска.Логин = Логин) Тогда
			НашлиУзел = Истина;
		КонецЕсли;
		
		Если НЕ НашлиУзел Тогда
			Продолжить;
		КонецЕсли;
		
		Результат = Новый Структура;
		Результат.Вставить("ВнутреннийИдентификатор", ПолучитьАтрибутУзлаXML(УзелDSS, "ИдентификаторСервиса", ""));
		Результат.Вставить("Логин", ПолучитьАтрибутУзлаXML(УзелDSS, "ИмяПользователя", ""));
		Результат.Вставить("ТелефонМобильный", ПолучитьАтрибутУзлаXML(УзелDSS, "ТелефонМобильный", ""));
		Результат.Вставить("ЭлектроннаяПочта", ПолучитьАтрибутУзлаXML(УзелDSS, "ЭлектроннаяПочта", ""));
		Результат.Вставить("Отпечаток", Отпечаток);
		Результат.Вставить("РежимАутентификации", ПолучитьАтрибутУзлаXML(УзелDSS, "РежимАутентификации", ""));
		Результат.Вставить("СрокQRКода", ПолучитьАтрибутУзлаXML(УзелDSS, "СрокДействияQRКода", '00010101'));
		
		УзелДействий = ПолучитьЭлементУзлаDOM(Узел, "ДействияОблачнойПодписи", Ложь);
		ВсеДействия = Новый Массив;
		Для СчетчикДействий = 0 По УзелДействий.Количество() - 1 Цикл
			ТекущееДействие = ЗначениеУзлаXML(УзелДействий[СчетчикДействий], "ДействиеОблачнойПодписи", "");
			ВсеДействия.Добавить(ТекущееДействие);
		КонецЦикла;
		Результат.Вставить("Действия", СтрСоединить(ВсеДействия, ","));
		
		Если СерверDSS <> Неопределено Тогда
			
			ВсеВерсии = СервисКриптографииDSSКлиентСервер.ПоддерживаемыеВерсии();
			ОписаниеСервиса = ПолучитьОписаниеСервисаОблачнойПодписи();

			АдресСервера = ПолучитьАтрибутУзлаXML(СерверDSS, "АдресDSS", "");
			
			ОписаниеСервиса.Наименование = АдресСервера;
			ОписаниеСервиса.АдресСервера = АдресСервера;
			ОписаниеСервиса.СервисПодписи = ПолучитьАтрибутУзлаXML(СерверDSS, "АдресСЭП", "");
			ОписаниеСервиса.СервисИдентификации = ПолучитьАтрибутУзлаXML(СерверDSS, "АдресЦентраИдентификации", "");
			ОписаниеСервиса.СервисПроверки = ПолучитьАтрибутУзлаXML(СерверDSS, "АдресСервисаПроверки", "");
			ОписаниеСервиса.ИдентификаторЦИ = ПолучитьАтрибутУзлаXML(СерверDSS, "ИдентификаторЦИ", "");
			ОписаниеСервиса.ИдентификаторСЭП = ПолучитьАтрибутУзлаXML(СерверDSS, "ИдентификаторСЭП", "");
			ОписаниеСервиса.ВнутреннийИдентификатор = ПолучитьАтрибутУзлаXML(СерверDSS, "ИдентификаторDSS", "");
			
			ОписаниеСервиса.Используется = Истина;
			ОписаниеСервиса.ТаймАут = 120;
			ОписаниеСервиса.ВерсияАПИ = ВсеВерсии[0];
			ОписаниеСервиса.АдресЛичногоКабинета = ПолучитьАтрибутУзлаXML(СерверDSS, "АдресЛичногоКабинета", "");
			
			ОграничениеАвторизации = Новый Массив;
			Если Результат.РежимАутентификации = "ПарольМобильноеПриложение" Тогда
				СоответствиеТипов = СпособыАвторизацииОблачнойПодписи();
				ВариантАутентификации = 2;
				СпособАвторизации = 9;
				
				ОграничениеАвторизации.Добавить(СоответствиеТипов[ВариантАутентификации]);
				ОграничениеАвторизации.Добавить(СоответствиеТипов[СпособАвторизации]);
				
			КонецЕсли;
			
			ОписаниеСервиса.ОграничениеАвторизации = СтрСоединить(ОграничениеАвторизации, ",");
			
			Результат.Вставить("Сервер", ОписаниеСервиса);
			
		Иначе
			ПараметрыФункции = Новый Структура();
			ПараметрыФункции.Вставить("ВнутреннийИдентификатор", Результат.ВнутреннийИдентификатор); 
			МассивСерверов = ОбменССерверомСписокСерверовОблачнойПодписи(ПараметрыФункции);
			Если МассивСерверов.Количество() > 0 Тогда
				Результат.Вставить("Сервер", МассивСерверов[0]);
			КонецЕсли;
		КонецЕсли;	
		
		Прервать;
		
	КонецЦикла;
	
	Если Результат <> Неопределено Тогда
		РежимАутентификации = СпособыАвторизацииОблачнойПодписи()[Результат.РежимАутентификации];
		УчетнаяЗаписьОблачнойПодписи = СоздатьУчетнуюЗаписьОблачнойПодписи(
					Результат.Сервер, 
					Результат.Логин,
					РежимАутентификации,
					ОбновлятьДанные);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(УчетнаяЗаписьОблачнойПодписи) Тогда
		Результат.Вставить("УчетнаяЗаписьОблачнойПодписи", УчетнаяЗаписьОблачнойПодписи);
	Иначе
		Результат = Неопределено;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Запрос состояния обработки заявления, в случае одобрения возвращает данные для автоматических настроек.
//
// Параметры:
//  Программа 							- СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//            							- СправочникСсылка.УчетныеЗаписиDSS
//  ИдентификаторДокументооборота		- Строка - идентификатор отправленного заявления
//  КлючПоиска							- см. КлючПоискаУчетнойЗаписи
//
// Возвращаемое значение:
//  Структура:
//    * Выполнено					- Булево
//    * РегистрацияУспешна			- Булево
//    * Ошибка						- Строка
//    * ДанныеОтвета				- ДвоичныеДанные
//    								- Неопределено
//    * ДанныеШифрованногоБлока		- ДвоичныеДанные
//    								- Неопределено
//    * ДанныеСертификата			- ДвоичныеДанные
//    								- Неопределено
//    * ДанныеКорневогоСертификата	- ДвоичныеДанные
//    								- Неопределено
//    * Программа					- СправочникСсылка.УчетныеЗаписиDSS - созданный или обновленный элемент справочника 
//    * ИдентификаторАбонента		- Строка
//    * СрокQRКода					- Дата
//    * НомерТелефона				- Строка
//    * ЭлектроннаяПочта			- Строка
//    * Действия					- Строка
//
Функция ПолучитьСостояниеЗаявления(Программа, ИдентификаторДокументооборота, КлючПоиска = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Выполнено", Ложь);
	Результат.Вставить("ДанныеОтвета", Неопределено);
	Результат.Вставить("ДанныеШифрованногоБлока", Неопределено);
	Результат.Вставить("ДанныеСертификата", Неопределено);
	Результат.Вставить("ДанныеКорневогоСертификата", Неопределено);
	Результат.Вставить("Ошибка", "");
	Результат.Вставить("ИдентификаторАбонента", "");
	Результат.Вставить("Программа", Программа);
	Результат.Вставить("РегистрацияУспешна", Ложь);
	Результат.Вставить("СрокQRКода", '00010101');
	Результат.Вставить("НомерТелефона", "");
	Результат.Вставить("ЭлектроннаяПочта", "");
	Результат.Вставить("Действия", "");
	
	ВсеАдреса = АдресаСервисовОбработкиЗаявления();
	
	ШаблонОписанияОшибки =
		НСтр("ru = 'Не удалось обновить состояние по причине'") + ": ";
	
	Попытка
		ВебСервис = ВебСервисУЦ(ВсеАдреса.ВебСервис, "http://regservice.keydisk.ru/", "RegService");
		Ответ = ВебСервис.ReceivePacket(Строка(ИдентификаторДокументооборота));
		
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОписанияОшибки,
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		Возврат Результат;
		
	КонецПопытки;
	
	Если Не ЗначениеЗаполнено(Ответ) Тогда
		Результат.Ошибка = ШаблонОписанияОшибки
						+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Метод %1 сервиса 1С:Подпись вернул пустой ответ.'"),
						"ReceivePacket");
		Возврат Результат;
	КонецЕсли;
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(Ответ);
	ПостроительDOM = Новый ПостроительDOM();
	ПостроительDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	ЧтениеXML.Закрыть();
	
	УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("code");
	КодРезультата = УзелDOM[0].ТекстовоеСодержимое;
	
	ИмяФайлаПакетОтвета = "";
	Если КодРезультата = "0" Тогда
		УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("packet");
		
		Если УзелDOM.Количество() > 0 Тогда
			
			ДвоичныеДанные = Base64Значение(УзелDOM[0].ТекстовоеСодержимое);
			ИмяФайлаПакетОтвета = ПолучитьИмяВременногоФайла(".zip");
			ДвоичныеДанные.Записать(ИмяФайлаПакетОтвета);
			
			Результат.ДанныеОтвета = ДвоичныеДанные;
			
		Иначе
		Результат.Ошибка = ШаблонОписанияОшибки
						+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Метод %1 сервиса 1С:Подпись вернул пустые данные.'"),
						"ReceivePacket");
		КонецЕсли;
		
	ИначеЕсли КодРезультата = "1" Тогда
		Результат.Ошибка = НСтр("ru = 'Заявление еще не обработано, попробуйте позже.'");
	Иначе
		УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("errorMessage");
		Если УзелDOM.Количество() > 0 Тогда
			Результат.Ошибка = УзелDOM[0].ТекстовоеСодержимое;
		Иначе
		Результат.Ошибка = ШаблонОписанияОшибки
						+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Метод %1 сервиса 1С:Подпись вернул код ошибки: %2'"),
						"ReceivePacket",
						Строка(КодРезультата));
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		Возврат Результат;
	КонецЕсли;
	
	ВременныйКаталог = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(
		ПолучитьИмяВременногоФайла("package"));
	
	СоздатьКаталог(ВременныйКаталог);
	
	ФайлНайден = Ложь;
	Попытка
		Архив1 = Новый ЧтениеZipФайла(ИмяФайлаПакетОтвета);
		
		Для Счетчик = 0 По Архив1.Элементы.Количество() - 1 Цикл
			
			Если Архив1.Элементы[Счетчик].Расширение = "bin" Тогда
				ФайлНайден = Истина;
				
				Архив1.Извлечь(Архив1.Элементы[Счетчик], ВременныйКаталог);
				Архив2 = Новый ЧтениеZipФайла(ВременныйКаталог + Архив1.Элементы[Счетчик].Имя);
				Архив2.ИзвлечьВсе(ВременныйКаталог);
				
				ЧтениеXML = Новый ЧтениеXML;
				ЧтениеXML.ОткрытьФайл(ВременныйКаталог + "file");
				ПостроительDOM = Новый ПостроительDOM;
				ДокументDOM  = ПостроительDOM.Прочитать(ЧтениеXML);
				ЧтениеXML.Закрыть();
				
				Результат.РегистрацияУспешна = Булево(ЗначениеУзлаXML(ДокументDOM, "РегистрацияУспешна"));
				
				Если Результат.РегистрацияУспешна Тогда
					Результат.ИдентификаторАбонента = ЗначениеУзлаXML(ДокументDOM, "ИдентификаторАбонента");
				Иначе
					Результат.Ошибка = ЗначениеУзлаXML(ДокументDOM, "Результат"); 
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		Если Не ФайлНайден Тогда
			ВызватьИсключение НСтр("ru = 'Архив не содержит файл данных.'");
		КонецЕсли;
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Ошибка = ШаблонОписанияОшибки
						+ СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Не удалось разобрать результат выполнения метода %1 сервиса 1С:Подпись по причине: %2'"),
						"ReceivePacket",
						ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	КонецПопытки;
	
	УдалитьФайлы(ИмяФайлаПакетОтвета);
	УдалитьФайлы(ВременныйКаталог);
	
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если Не Результат.РегистрацияУспешна Тогда
		Результат.Выполнено = Истина;
		Возврат Результат;
	КонецЕсли;
	
	// Запрос сертификата.
	
	Ответ = ВебСервис.ReceiveUpdatedPacket(Строка(Результат.ИдентификаторАбонента), Дата('00010101'));
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(Ответ);
	ПостроительDOM = Новый ПостроительDOM();
	ПостроительDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	ЧтениеXML.Закрыть();
	
	УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("code");
	КодРезультата = УзелDOM[0].ТекстовоеСодержимое;
	
	ИмяФайлаПакетОтвета = "";
	Если КодРезультата = "0" Тогда
		УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("packet");
		
		Если УзелDOM.Количество() > 0 Тогда
			
			ДвоичныеДанные = Base64Значение(УзелDOM[0].ТекстовоеСодержимое);
			ИмяФайлаПакетОтвета = ПолучитьИмяВременногоФайла(".zip");
			ДвоичныеДанные.Записать(ИмяФайлаПакетОтвета);
			
			Результат.ДанныеОтвета = ДвоичныеДанные;
			
		Иначе
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Метод %1 сервиса 1С:Подпись вернул пустые данные.'"),
						"ReceiveUpdatedPacket");
		КонецЕсли;
	Иначе
		УзелDOM = ПостроительDOM.ПолучитьЭлементыПоИмени("errorMessage");
		Если УзелDOM.Количество() > 0 Тогда
			Результат.Ошибка = УзелDOM[0].ТекстовоеСодержимое;
		Иначе
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Метод %1 сервиса 1С:Подпись вернул код ошибки: %2'"),
						"ReceiveUpdatedPacket",
						Строка(КодРезультата));
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		Возврат Результат;
	КонецЕсли;
	
	ВременныйКаталог = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(
		ПолучитьИмяВременногоФайла("package"));
	
	СоздатьКаталог(ВременныйКаталог);
	
	ФайлНайден = Ложь;
	
	Попытка
		Архив = Новый ЧтениеZipФайла(ИмяФайлаПакетОтвета);
		
		Для Счетчик = 0 По Архив.Элементы.Количество() - 1 Цикл
			
			Если Архив.Элементы[Счетчик].Расширение = "xml" Тогда
				ФайлНайден = Истина;
				
				Архив.Извлечь(Архив.Элементы[Счетчик], ВременныйКаталог);
				
				ЧтениеXML = Новый ЧтениеXML;
				ЧтениеXML.ОткрытьФайл(ВременныйКаталог + Архив.Элементы[Счетчик].Имя); 
				ПостроительDOM = Новый ПостроительDOM;
				ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
				ЧтениеXML.Закрыть();
				
				УзелDOM = ДокументDOM.ПолучитьЭлементыПоИмени("Сертификат");
				
				СертификатСтрокой = "";
				КорневойСертификатСтрокой = "";
				
				Для Каждого Узел Из УзелDOM Цикл
					Хранилище = Узел.Атрибуты.ПолучитьИменованныйЭлемент("Хранилище").ТекстовоеСодержимое;
					Если Хранилище = "MY" Тогда
						СертификатСтрокой = Узел.ТекстовоеСодержимое;
					КонецЕсли;
					Если Хранилище = "ROOT" Тогда
						КорневойСертификатСтрокой = Узел.ТекстовоеСодержимое;
					КонецЕсли;
				КонецЦикла;
				
				Если Не ЗначениеЗаполнено(СертификатСтрокой) Тогда
					ВызватьИсключение НСтр("ru = 'Ответ не содержит сведений о выпущенном сертификате.'");
				ИначеЕсли Не ЗначениеЗаполнено(КорневойСертификатСтрокой) Тогда
					ВызватьИсключение НСтр("ru = 'Ответ не содержит сведений о корневом сертификате.'");
				КонецЕсли;
				
				Результат.ДанныеСертификата          = Base64Значение(СертификатСтрокой);
				Результат.ДанныеКорневогоСертификата = Base64Значение(КорневойСертификатСтрокой);
				
			КонецЕсли;
		КонецЦикла;
		
		Если Не ФайлНайден Тогда
			ВызватьИсключение НСтр("ru = 'Архив не содержит файл данных.'");
		КонецЕсли;
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось разобрать результат выполнения метода %1 сервиса 1С:Подпись по причине: %2'"),
					"ReceiveUpdatedPacket",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	КонецПопытки;
	
	УдалитьФайлы(ИмяФайлаПакетОтвета);
	УдалитьФайлы(ВременныйКаталог);
	
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если ТипЗнч(Программа) = СервисКриптографииDSSКлиентСервер.ПолучитьТипОблачнойПодписи() Тогда
		Попытка
			РезультатОбновления = ОбновитьДанныеОблачнойПодписиВУчетнойЗаписи(ДокументDOM, КлючПоиска, Истина);
			Если РезультатОбновления = Неопределено Тогда
				ВызватьИсключение НСтр("ru = 'Не удалось зарегистрировать учетную запись DSS.'");
			ИначеЕсли ЗначениеЗаполнено(Программа) И Программа <> РезультатОбновления.УчетнаяЗаписьОблачнойПодписи Тогда
				ВызватьИсключение НСтр("ru = 'Выбранная учетная запись DSS не соответствуют регистрационным данным.'");
			ИначеЕсли Программа <> РезультатОбновления.УчетнаяЗаписьОблачнойПодписи Тогда
				Результат.Программа = РезультатОбновления.УчетнаяЗаписьОблачнойПодписи;
			КонецЕсли;
			Результат.СрокQRКода = РезультатОбновления.СрокQRКода;
			Результат.НомерТелефона = РезультатОбновления.ТелефонМобильный;
			Результат.ЭлектроннаяПочта = РезультатОбновления.ЭлектроннаяПочта;
			Результат.Действия = РезультатОбновления.Действия;
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось разобрать результат выполнения метода %1 сервиса 1С:Подпись по причине: %2'"),
					"ReceiveUpdatedPacket",
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		КонецПопытки;	
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.Ошибка) Тогда
		Возврат Результат;
	КонецЕсли;
	
	УзелЗакрытойИнформации = ДокументDOM.ПолучитьЭлементыПоИмени("КонфиденциальнаяИнформация");
	Если УзелЗакрытойИнформации <> Неопределено Тогда
		Результат.ДанныеШифрованногоБлока = Base64Значение(УзелЗакрытойИнформации[0].ТекстовоеСодержимое);
	КонецЕсли;	
	
	Результат.Выполнено = Истина;
	
	Возврат Результат;
	
КонецФункции

// Получает данные из предыдущего заявления на выпуск квалифицированного заявления связанного с этой программой
//
// Параметры:
//  Программа 			- СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//            			- СправочникСсылка.УчетныеЗаписиDSS
//  СсылкаСертификата   - Неопределено
//                      - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//
// Возвращаемое значение:
//  Структура:
//    * ОблачнаяПодписьМобильныйТелефон 	- Строка
//    * ОблачнаяПодписьЭлектроннаяПочта 	- Строка
//    * ИНН									- Строка
//    * КПП									- Строка
//    * ИдентификаторАбонента				- Строка
//    * ОтпечатокСертификата				- Строка
//    * СрокQRКода							- Дата
//
Функция ПолучитьДанныеИзПредыдущегоЗаявленияНаСертификат(Программа, СсылкаСертификата = Неопределено) Экспорт
	
	ДанныеЗаявления = Новый Структура();
	ДанныеЗаявления.Вставить("ИдентификаторАбонента", "");
	ДанныеЗаявления.Вставить("ОблачнаяПодписьМобильныйТелефон", "");
	ДанныеЗаявления.Вставить("ОблачнаяПодписьМобильныйТелефонXML", "");
	ДанныеЗаявления.Вставить("ОблачнаяПодписьЭлектроннаяПочта", "");
	ДанныеЗаявления.Вставить("ИНН", "");
	ДанныеЗаявления.Вставить("КПП", "");
	ДанныеЗаявления.Вставить("ОтпечатокСертификата", "");
	ДанныеЗаявления.Вставить("СрокQRКода", '00010101');
		
	Если Метаданные.Обработки.Найти("ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата") <> Неопределено
		И Метаданные.Справочники.Найти("СертификатыКлючейЭлектроннойПодписиИШифрования") <> Неопределено Тогда
		
		ТекстЗапроса =
		"ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	СертификатыКлючейЭлектроннойПодписиИШифрования.Отпечаток КАК Отпечаток,
		|	ЕСТЬNULL(ЗаявленияНаВыпускСертификата.СодержаниеЗаявления, Неопределено) КАК СодержаниеЗаявления
		|ИЗ
		|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК СертификатыКлючейЭлектроннойПодписиИШифрования
		|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЗаявленияНаВыпускСертификата КАК ЗаявленияНаВыпускСертификата
		|		ПО ЗаявленияНаВыпускСертификата.Сертификат = СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка
		|ГДЕ
		|	СертификатыКлючейЭлектроннойПодписиИШифрования.Программа = &Программа
		|	И (&СсылкаСертификата = НЕОПРЕДЕЛЕНО
		|	ИЛИ СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка <> &СсылкаСертификата)
		|УПОРЯДОЧИТЬ ПО
		|	СертификатыКлючейЭлектроннойПодписиИШифрования.ДействителенДо УБЫВ";
		
		Запрос = Новый Запрос;
		Запрос.Текст = ТекстЗапроса;
		Запрос.УстановитьПараметр("Программа", Программа);
		Запрос.УстановитьПараметр("СсылкаСертификата", СсылкаСертификата);
		
		СведенияОЗаявлении = Запрос.Выполнить().Выбрать();
		
		РеквизитыЗаявления = Неопределено;
		Пока СведенияОЗаявлении.Следующий() Цикл
			
			Если ЗначениеЗаполнено(СведенияОЗаявлении.Отпечаток) Тогда
				ДанныеОтпечатка = Base64Значение(СведенияОЗаявлении.Отпечаток);
				ДанныеЗаявления.ОтпечатокСертификата = НРег(ПолучитьHexСтрокуИзДвоичныхДанных(ДанныеОтпечатка));
			КонецЕсли;
			
			Если СведенияОЗаявлении.СодержаниеЗаявления <> Неопределено Тогда
				РеквизитыЗаявления = СведенияОЗаявлении.СодержаниеЗаявления.Получить();
				Если ТипЗнч(РеквизитыЗаявления) = Тип("Структура") Тогда
					Прервать;
				КонецЕсли;
			КонецЕсли;
			
		КонецЦикла;
		
	КонецЕсли;
		
	Если РеквизитыЗаявления <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(ДанныеЗаявления, РеквизитыЗаявления);
	КонецЕсли;
	
	Возврат ДанныеЗаявления;
	
КонецФункции

// Формируем текст заявления на изменение параметров подключения к серверу облачной подписи
//
// Параметры:
//  РеквизитыЗаявления  - см. СтруктураРеквизитовЗаявления
//  Программа 			- СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//            			- СправочникСсылка.УчетныеЗаписиDSS
//  ТикетПользователя	- Строка
//
// Возвращаемое значение:
//  Строка
//
Функция ПодготовитьЗаявлениеXML(РеквизитыЗаявления, Программа, ТикетПользователя) Экспорт
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку("windows-1251");
	ЗаписьXML.ЗаписатьОбъявлениеXML();
	
	// АПК:1036-выкл - сторонний сервис
	ЗаписьXML.ЗаписатьНачалоЭлемента("Заявление");
	ЗаписьXML.ЗаписатьАтрибут("ВерсФорм", "2.5");
	ЗаписьXML.ЗаписатьАтрибут("ДатаВремяФормирования", XMLСтрока(ТекущаяДатаСеанса()));
	ЗаписьXML.ЗаписатьАтрибут("ВерсПрог", "1С");
	
		ЗаписатьУзелXML(ЗаписьXML, "УчетнаяЗапись", РеквизитыЗаявления.ИдентификаторАбонента, Истина);
		ЗаписатьУзелXML(ЗаписьXML, "ТипЗаявления", "2");
		ЗаписатьУзелXML(ЗаписьXML, "ИНН", РеквизитыЗаявления.ИНН, Истина);
		ЗаписатьУзелXML(ЗаписьXML, "КПП", РеквизитыЗаявления.КПП, Истина);
		
		ЗаписьXML.ЗаписатьНачалоЭлемента("ВладельцыЭЦП");
		ЗаписьXML.ЗаписатьНачалоЭлемента("ВладелецЭЦП");
		
			ЗаписьРазделаУчетнойЗаписиОблачнойПодписи(ЗаписьXML, РеквизитыЗаявления, Программа);
			
		ЗаписьXML.ЗаписатьКонецЭлемента(); // КонецЭлемента ВладелецЭЦП.
		ЗаписьXML.ЗаписатьКонецЭлемента(); // КонецЭлемента ВладельцыЭЦП.
		
		ЗаписатьУзелXML(ЗаписьXML, "БилетПользователя", ТикетПользователя, Истина);
		
	// АПК:1036-вкл - сторонний сервис
	
	ЗаписьXML.ЗаписатьКонецЭлемента(); // КонецЭлемента Заявление.
	
	Результат = ЗаписьXML.Закрыть();
	
	Возврат Результат;
	
КонецФункции

// Дополняет текст заявления на изменение параметров подключения сведениями об учетной записи облачной подписи
//
// Параметры:
//  ЗаписьXML			- ЗаписьXML
//  РеквизитыЗаявления  - см. СтруктураРеквизитовЗаявления
//  Программа 			- СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования
//            			- СправочникСсылка.УчетныеЗаписиDSS
//  Логин				- Строка - для новой учетной записи
//  Сервер				- Строка - для новой учетной записи
//
Процедура ЗаписьРазделаУчетнойЗаписиОблачнойПодписи(ЗаписьXML, РеквизитыЗаявления, Программа, Логин = "", Сервер = "") Экспорт
	
	Если СервисКриптографииDSSКлиентСервер.ПолучитьТипОблачнойПодписи() <> ТипЗнч(Программа) Тогда
		Возврат;
	КонецЕсли;
	
	НоваяУчетнаяЗапись = НЕ ЗначениеЗаполнено(Программа);
	МобильныйТелефонБезРазделителей = СервисКриптографииDSSСлужебный.ТелефонМобильныйБезРазделителей(РеквизитыЗаявления.НомерТелефона);
	ЭлектроннаяПочта = РеквизитыЗаявления.ЭлектроннаяПочта;
	УдостоверяющийЦентр = "ООО ""НПЦ ""1С"""; // АПК:1297 Не локализуется (формат веб-сервиса).

	МассивДействий = Новый Массив;
	
	Если НоваяУчетнаяЗапись Тогда
		МассивДействий.Добавить("Создать");
	Иначе
		НашлиСтроку = СервисКриптографииDSS.ПолучитьВсеУчетныеЗаписи(Программа);
		Если НашлиСтроку.Количество() = 0 Тогда
			Возврат;
		КонецЕсли;	
		Логин = НашлиСтроку[0].Логин;
		Сервер = НашлиСтроку[0].ВнутреннийИдентификатор;
		МассивДействий.Добавить("Использовать");
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_ИзданиеСертификата Тогда
		МассивДействий.Добавить("СменитьСертификат");
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_СменаКонтактов Тогда
		МассивДействий.Добавить("СменитьКонтакты");
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_ПовторнаяОтправкаКлючМобильногоПриложения Тогда
		МассивДействий.Добавить("ОтправитьКлюч" + "myDSS"); // АПК:1297 Не локализуется (формат веб-сервиса).
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_ПовторнаяОтправкаКодаАктивации Тогда
		МассивДействий.Добавить("ОтправитьКодАктивации");
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_СменаКлючаМобильногоПриложения Тогда
		МассивДействий.Добавить("СменитьКлюч" + "myDSS"); // АПК:1297 Не локализуется (формат веб-сервиса).
	КонецЕсли;
	
	Если РеквизитыЗаявления.Режим_СменаПароля Тогда
		МассивДействий.Добавить("СменитьПароль");
	КонецЕсли;
	
	// общий блок
	ЗаписьXML.ЗаписатьНачалоЭлемента("ПараметрыГенерацииСертификатаВDSS");
	ЗаписьXML.ЗаписатьАтрибут("УдостоверяющийЦентр", УдостоверяющийЦентр);
		
	ЗаписьXML.ЗаписатьНачалоЭлемента("ОперацииУчетнойЗаписиDSS");
	Для Каждого СтрокаМассива Из МассивДействий Цикл
		ЗаписатьУзелXML(ЗаписьXML, "ОперацияУчетнойЗаписиDSS", СтрокаМассива);
	КонецЦикла;	
	ЗаписьXML.ЗаписатьКонецЭлемента();
	
	// блок информации об учетной записи
	Если НоваяУчетнаяЗапись Тогда
		ЗаписьXML.ЗаписатьНачалоЭлемента("НоваяУчетнаяЗаписьDSS");
	Иначе
		ЗаписьXML.ЗаписатьНачалоЭлемента("УчетнаяЗаписьDSS");
	КонецЕсли;
	ЗаписатьУзелXML(ЗаписьXML, "ИдентификаторСервиса", Сервер);
	ЗаписатьУзелXML(ЗаписьXML, "ИмяПользователя", Логин);
	ЗаписатьУзелXML(ЗаписьXML, "МобильныйТелефон", МобильныйТелефонБезРазделителей, Истина);
	ЗаписатьУзелXML(ЗаписьXML, "ЭлектроннаяПочта", ЭлектроннаяПочта, Истина);
	ЗаписьXML.ЗаписатьКонецЭлемента();
	
	ЗаписьXML.ЗаписатьКонецЭлемента();
	
КонецПроцедуры

// Анализ номера мобильного телефона на российский стандарт
//
// Параметры:
//  Телефон - Строка
//
// Возвращаемое значение:
//  Строка 
//
Функция ПолучитьПредставлениеТелефона(Телефон) Экспорт
		
	Представление = "";
	
	ТолькоЦифры = ЗначениеПоПредставлениюТелефона(Телефон);
	
	Если СтрДлина(ТолькоЦифры) = 10 Тогда
		Представление = СтрШаблон(
			"+7 (%1) %2-%3-%4", 
			Сред(ТолькоЦифры, 1, 3), 
			Сред(ТолькоЦифры, 4, 3),
			Сред(ТолькоЦифры, 7, 2),
			Сред(ТолькоЦифры, 9));		
	КонецЕсли;
	
	Возврат Представление;	

КонецФункции

// Анализ номера мобильного телефона на российский стандарт
//
// Параметры:
//  Телефон - Строка
//
// Возвращаемое значение:
//  Строка
//
Функция ЗначениеПоПредставлениюТелефона(Телефон) Экспорт
		
	ТекстДляОбработки = СокрЛП(Телефон);
	
	ТолькоЦифры = "";
	Для Индекс = 1 По СтрДлина(ТекстДляОбработки) Цикл
		ТекущийСимвол = Сред(ТекстДляОбработки, Индекс, 1);
		Если СтрНайти("0123456789", ТекущийСимвол) Тогда
			ТолькоЦифры = ТолькоЦифры + ТекущийСимвол;
		КонецЕсли;
	КонецЦикла;
	
	Если СтрДлина(ТолькоЦифры) = 11 
		И (Сред(ТолькоЦифры, 1, 1) = "7" ИЛИ Сред(ТолькоЦифры, 1, 1) = "8") Тогда
		ТолькоЦифры = Сред(ТолькоЦифры, 2);
	КонецЕсли;

	Возврат ТолькоЦифры;	

КонецФункции

#КонецОбласти

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция УстановитьСоединениеССерверомИнтернета(URLСервера, ОписаниеОшибки = "", Таймаут = 60)

	СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(URLСервера);
	Схема = ?(ЗначениеЗаполнено(СтруктураURI.Схема), СтруктураURI.Схема, "http");
	Прокси = ПолучениеФайловИзИнтернета.ПолучитьПрокси(Схема);
	
	Попытка
		Соединение = Новый HTTPСоединение(
			СтруктураURI.Хост,
			СтруктураURI.Порт,
			СтруктураURI.Логин,
			СтруктураURI.Пароль, 
			Прокси,
			Таймаут,
			?(НРег(Схема) = "http", Неопределено, ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение()));
	Исключение
			
		ИнформацияОбОшибке = ПолучитьИнформациюОбОшибке(ИнформацияОбОшибке());
		ВидОперации = НСтр("ru = 'Установление соединения с сервером интернета.'", ОбщегоНазначения.КодОсновногоЯзыка());
			
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		ПодготовитьРезультатВызова(ОписаниеОшибки, Неопределено, ВидОперации); 
		
		Возврат Неопределено;
	КонецПопытки;
	
	Возврат Соединение;
	
КонецФункции

Функция ВыполнитьЗапросREST(ПараметрыПодключения, ПараметрыМетода = Неопределено, МетодЗапроса = "GET", Заголовки = Неопределено)
	
	Результат = Новый Структура("Выполнено, Ошибка, Результат", Ложь, "", Неопределено);
	
	Путь = ПараметрыПодключения.ТочкаПодключения;
	
	ПараметрыЗапроса = Неопределено;
	
	Если Заголовки = Неопределено Тогда
		Заголовки = Новый Соответствие;
	КонецЕсли;	
	
	Если ПараметрыМетода <> Неопределено Тогда
		ПараметрыЗапроса = "";
		Если МетодЗапроса = "GET" Тогда
			Для Каждого СтрокаКлюча Из ПараметрыМетода Цикл
				ПараметрыЗапроса = ПараметрыЗапроса + ?(ПустаяСтрока(ПараметрыЗапроса), "", "&");
				ЗначениеПараметра = СтрокаКлюча.Значение;
				ПараметрыЗапроса = ПараметрыЗапроса + СтрокаКлюча.Ключ + "=" + ЗначениеПараметра;
			КонецЦикла;
			Путь = Путь + ?(ПустаяСтрока(ПараметрыЗапроса), "", "?" + ПараметрыЗапроса);
		ИначеЕсли ТипЗнч(ПараметрыМетода) <> Тип("Строка") Тогда
			ПараметрыЗапроса = ОбщегоНазначения.ЗначениеВJSON(ПараметрыМетода);
		Иначе
			ПараметрыЗапроса = ПараметрыМетода;
		КонецЕсли;
	КонецЕсли;
	
	Попытка 
		Соединение = УстановитьСоединениеССерверомИнтернета(ПараметрыПодключения.АдресСервера);
		
		Запрос = Новый HTTPЗапрос(Путь, Заголовки);
		
		Если ПараметрыЗапроса <> Неопределено Тогда
			Запрос.УстановитьТелоИзСтроки(ПараметрыЗапроса);
		КонецЕсли;	
		
		ОтветСервиса = Соединение.ВызватьHTTPМетод(МетодЗапроса, Запрос);
		
		ТелоКакСтрока = ОтветСервиса.ПолучитьТелоКакСтроку();
		
		Если ОтветСервиса.КодСостояния = 200 Тогда
			Результат.Результат = ОбщегоНазначения.JSONВЗначение(ТелоКакСтрока, , Ложь);
			Результат.Выполнено = Истина;
		Иначе
			Результат.Ошибка = ТелоКакСтрока;
		КонецЕсли;
		
	Исключение
		ДанныеОшибки = ИнформацияОбОшибке();
		ВидОперации = НСтр("ru = 'Вызов REST сервиса.'", ОбщегоНазначения.КодОсновногоЯзыка())
					 + ПараметрыПодключения.АдресСервера;
		Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ДанныеОшибки);
		ПодготовитьРезультатВызова(Результат.Ошибка, Неопределено, ВидОперации); 
		
	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции	

Функция ВебСервисУЦ(АдресВебСервиса, ПространствоИмен, ИмяСервиса)
	
	ПараметрыПодключения = ОбщегоНазначения.ПараметрыПодключенияWSПрокси();
	ПараметрыПодключения.АдресWSDL = АдресВебСервиса;
	ПараметрыПодключения.URIПространстваИмен = ПространствоИмен;
	ПараметрыПодключения.ИмяСервиса = ИмяСервиса;
	ПараметрыПодключения.Таймаут = 7;
	
	Возврат ОбщегоНазначения.СоздатьWSПрокси(ПараметрыПодключения);
	
КонецФункции

// Возвращает описание всех сервисов используемые в обработке заявления
//
// Возвращаемое значение:
//  Структура
//
Функция АдресаСервисовОбработкиЗаявления()
	
	Результат = Новый Структура;
	Результат.Вставить("СписокСерверовDSS", "/api/v1/dssapi/GetDssList");
	Результат.Вставить("ПроверитьЛогинDSS", "/api/v1/dssuserinfo/CheckLogin");
	Результат.Вставить("АктивироватьПароль", "/api/v1/dssapi/ActivatePassword?skid=%1&guid=%2");
	Результат.Вставить("АктивироватьКлючМобильногоПриложения", "/api/v1/dssapi/ActivateKeyAndGetActivationCode?skid=%1&guid=%2");
	Результат.Вставить("СвойствоУчетнойЗаписи", "/api/v1/dssapi/PropertyLogin");
	Результат.Вставить("ОтправитьКодАктивацииКлюча", "/api/v1/dssapi/GetActivationCode?skid=%1&guid=%2");
	
	Результат.Вставить("ВебСервис", "https://regservice.1c.ru/regservice/regservice.asmx?wsdl");
	
	Возврат Результат;
	
КонецФункции

Функция ПараметрыПодключенияСервисов(ТочкаПодключения)
	
	ВсеТочки = АдресаСервисовОбработкиЗаявления();
	
	Результат = Новый Структура;
	Результат.Вставить("АдресСервера", "http://regservice.1c.ru");
	Результат.Вставить("ТочкаПодключения", ВсеТочки[ТочкаПодключения]);
	
	Возврат Результат;
	
КонецФункции

Функция ПолучитьИнформациюОбОшибке(ИнформацияОбОшибке)
	
	Результат = ИнформацияОбОшибке;
	Если ИнформацияОбОшибке <> Неопределено Тогда
		Если ИнформацияОбОшибке.Причина <> Неопределено Тогда
			Результат = ПолучитьИнформациюОбОшибке(ИнформацияОбОшибке.Причина);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция СвойствоСтруктуры(Данные, КлючевоеПоле, ЗначениеПоУмолчанию = Неопределено)
	
	Возврат СервисКриптографииDSSКлиентСервер.ПолучитьПолеСтруктуры(Данные, КлючевоеПоле, ЗначениеПоУмолчанию)
	
КонецФункции

Функция ПолучитьОписаниеСервисаОблачнойПодписи()
	
	Результат = Новый Структура;
	Результат.Вставить("Ссылка", Новый(СервисКриптографииDSSКлиентСервер.ПолучитьТипОблачнойПодписи()));
	Результат.Вставить("Наименование", "");
	Результат.Вставить("АдресСервера", "");
	Результат.Вставить("АдресЛичногоКабинета", "");
	Результат.Вставить("СервисИдентификации", "");
	Результат.Вставить("СервисПодписи", "");
	Результат.Вставить("СервисПроверки", "");
	Результат.Вставить("ВнутреннийИдентификатор", "");
	Результат.Вставить("ИдентификаторЦИ", "");
	Результат.Вставить("ИдентификаторСЭП", "");
	Результат.Вставить("ШаблонПодтверждения", "");
	Результат.Вставить("ТаймАут", 120);
	Результат.Вставить("ВерсияАПИ", "");
	Результат.Вставить("Комментарий", "");
	Результат.Вставить("Используется", Истина);
	Результат.Вставить("ОграничениеАвторизации", "");
	Результат.Вставить("ПользовательШифрования", "");
	Результат.Вставить("ПарольПользовательШифрования", "");
	
	Возврат Результат;
	
КонецФункции

Функция СпособыАвторизацииОблачнойПодписи()
	
	Результат = Новый Соответствие;
	
	Результат.Вставить(5, "Вторичный_СМС"); // подтверждение по SMS
	Результат.Вставить(9, "Вторичный_МобильноеПриложение"); // подтверждение по myDSS
	Результат.Вставить(8, "Вторичный_ЭлектроннаяПочта"); // подтверждение по электронной почте
	Результат.Вставить(12, "Вторичный_AirKeyLite"); // подтверждение альтернативным мобильным приложением
	Результат.Вставить(3, "Первичный_УчетныеДанные"); // логин и пароль
	Результат.Вставить(-2, "Первичный_ДвухФакторная"); // аутентификация требует подтверждение
	Результат.Вставить(-1, "Первичный_КодАвторизации"); // особый способ пользователя
	Результат.Вставить(2, "Первичный_СертификатАвторизации");
	Результат.Вставить("ПарольМобильноеПриложение", "Первичный_ДвухФакторная"); // аутентификация требует подтверждение
	
	Возврат Результат;
	
КонецФункции	

Функция ПолучитьАтрибутУзлаXML(УзелDOM, НазваниеАтрибута, ЗначениеПоУмолчанию = "")
	
	Результат = ЗначениеПоУмолчанию;
	
	Если УзелDOM = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	НайденныйАтрибут = УзелDOM.Атрибуты.ПолучитьИменованныйЭлемент(НазваниеАтрибута);
	Если НайденныйАтрибут <> Неопределено Тогда
		Результат = НайденныйАтрибут.ТекстовоеСодержимое;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ПолучитьЭлементУзлаDOM(УзелВладелец, ИмяЭлемента, ТолькоОдин = Истина)
	
	Результат = Неопределено;
	
	НашлиУзлы = УзелВладелец.ПолучитьЭлементыПоИмени(ИмяЭлемента);
	Если НЕ ТолькоОдин Тогда
		Результат = НашлиУзлы;
	ИначеЕсли НашлиУзлы.Количество() = 1 Тогда
		Результат = НашлиУзлы[0];
	КонецЕсли;	
	
	Возврат Результат;
	
КонецФункции

Функция ЗначениеУзлаXML(ДокументDOM, НазваниеУзла, ЗначениеПоУмолчанию = "")
	
	НашлиЭлементы = ПолучитьЭлементУзлаDOM(ДокументDOM, НазваниеУзла, Ложь);
	Если НашлиЭлементы.Количество() = 0 Тогда
		Результат = ЗначениеПоУмолчанию;
	Иначе
		Результат = НашлиЭлементы[0].ТекстовоеСодержимое;		
	КонецЕсли;
	
	Если ТипЗнч(Результат) = Тип("Строка")
		И ЗначениеЗаполнено(Результат) Тогда
		Если ТипЗнч(ЗначениеПоУмолчанию) = Тип("Дата") Тогда
			Результат = XMLЗначение(Тип("Дата"), Результат);
		КонецЕсли;	
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ПакетЗаявления(ЗаявлениеXML, ИдентификаторДокументооборота, ПодписьЗаявления = Неопределено)
	
	// Подготовка пакета заявления.
	ВременныйКаталог = ОбщегоНазначенияКлиентСервер.ДобавитьКонечныйРазделительПути(
		ПолучитьИмяВременногоФайла("package"));
	
	СоздатьКаталог(ВременныйКаталог);
	
	МассивФайлов		= Новый Массив;
	ИмяФайлаЗаявления 	= НовыйСжатыйУникальныйИдентификатор() + ".bin";
	ИмяФайлаОписания  	= "packageDescription.xml";
	ИмяФайлаПакета    	= ИдентификаторДокументооборота + ".zip";
	
	ПодготовитьФайл(ЗаявлениеXML, ИмяФайлаЗаявления, ВременныйКаталог);
	МассивФайлов.Добавить(ИмяФайлаЗаявления);
	
	Если ЗначениеЗаполнено(ПодписьЗаявления) Тогда
		ИмяФайлаПодписи = НовыйСжатыйУникальныйИдентификатор() + ".bin";
		ПодготовитьФайл(ПодписьЗаявления, ИмяФайлаПодписи, ВременныйКаталог, "bin");
		МассивФайлов.Добавить(ИмяФайлаПодписи);
	КонецЕсли;	
	
	ОписаниеПакетаXML = ОписаниеПакетаXML(ИмяФайлаЗаявления, ИмяФайлаПодписи, ИдентификаторДокументооборота);
	ПодготовитьФайл(ОписаниеПакетаXML, ИмяФайлаОписания, ВременныйКаталог);
	МассивФайлов.Добавить(ИмяФайлаОписания);
	
	Результат = ПодготовитьФайлОтправки(МассивФайлов, ВременныйКаталог, ИмяФайлаПакета);
	
	УдалитьФайлы(ВременныйКаталог);
	
	Возврат Результат;
	
КонецФункции

Функция ПодготовитьФайлОтправки(МассивФайлов, ВременныйКаталог, ИмяФайлаПакета)
	
	ЗаписьАрхива = Новый ЗаписьZipФайла(ВременныйКаталог + ИмяФайлаПакета, , , , УровеньСжатияZIP.Максимальный);
	
	Для Каждого СтрокаМассива Из МассивФайлов Цикл
		ЗаписьАрхива.Добавить(ВременныйКаталог + СтрокаМассива);
	КонецЦикла;	
	ЗаписьАрхива.Записать();
	
	Результат = Base64Строка(Новый ДвоичныеДанные(ВременныйКаталог + ИмяФайлаПакета));
	
	Возврат Результат;
	
КонецФункции	

Функция ОписаниеПакетаXML(ИмяФайлаЗаявления, ИмяФайлаПодписи, ИдентификаторДокументооборота)
	
	ЗаписьXML = Новый ЗаписьXML;
	ЗаписьXML.УстановитьСтроку("windows-1251");
	ЗаписьXML.ЗаписатьОбъявлениеXML();
	
	// АПК:1036-выкл - сторонний сервис
	
	ЗаписьXML.ЗаписатьНачалоЭлемента("пакет");
	ЗаписьXML.ЗаписатьАтрибут("версияФормата", "1С:1.0");
	
	ЗаписьXML.ЗаписатьАтрибут("версПрог", "1.0"); // АПК:1297 Не локализуется (формат веб-сервиса).
	ЗаписьXML.ЗаписатьАтрибут("типДокументооборота", "РегистрацияАбонентаЭДО");
	ЗаписьXML.ЗаписатьАтрибут("типТранзакции", "Регистрация");
	ЗаписьXML.ЗаписатьАтрибут("идентификаторДокументооборота", ИдентификаторДокументооборота);
	
	
		ЗаписьXML.ЗаписатьНачалоЭлемента("отправитель");
		ЗаписьXML.ЗаписатьАтрибут("типСубъекта", "абонент");
		ЗаписьXML.ЗаписатьКонецЭлемента();
		
		ЗаписьXML.ЗаписатьНачалоЭлемента("получатель");
		ЗаписьXML.ЗаписатьАтрибут("идентификаторСубъекта", "КалугаАстрал");
		ЗаписьXML.ЗаписатьАтрибут("типСубъекта", "спецоператор");
		ЗаписьXML.ЗаписатьКонецЭлемента();
		
		ЗаписьXML.ЗаписатьНачалоЭлемента("документ");
		ЗаписьXML.ЗаписатьАтрибут("идентификаторДокумента", НовыйСжатыйУникальныйИдентификатор());
		ЗаписьXML.ЗаписатьАтрибут("типДокумента", "Заявление");
		ЗаписьXML.ЗаписатьАтрибут("типСодержимого", "xml");
		ЗаписьXML.ЗаписатьАтрибут("сжат", "false");
		ЗаписьXML.ЗаписатьАтрибут("зашифрован", "false");
		
			ЗаписьXML.ЗаписатьНачалоЭлемента("содержимое");
			ЗаписьXML.ЗаписатьАтрибут("имяФайла", ИмяФайлаЗаявления);
			ЗаписьXML.ЗаписатьКонецЭлемента();
		
		ЗаписьXML.ЗаписатьКонецЭлемента(); // КонецЭлемента документ.
		
		Если ЗначениеЗаполнено(ИмяФайлаПодписи) Тогда
			ЗаписьXML.ЗаписатьНачалоЭлемента("подпись");
			ЗаписьXML.ЗаписатьАтрибут("имяФайла", ИмяФайлаПодписи);
			ЗаписьXML.ЗаписатьКонецЭлемента();
		КонецЕсли;
		
	// АПК:1036-вкл - сторонний сервис
	
	ЗаписьXML.ЗаписатьКонецЭлемента(); // КонецЭлемента пакет.
	
	СтрокаXML = ЗаписьXML.Закрыть();
	
	Возврат СтрокаXML;
	
КонецФункции

Функция НовыйСжатыйУникальныйИдентификатор()
	
	Возврат НРег(СтрЗаменить(Строка(Новый УникальныйИдентификатор), "-", ""));
	
КонецФункции

Функция ПодготовитьРезультатВызова(Результат, АдресРезультата, ВидОперации)
	
	Если АдресРезультата <> Неопределено Тогда
		ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
	КонецЕсли;

	Если ТипЗнч(Результат) = Тип("Строка") Тогда
		ТекстОшибки = Результат;
	Иначе	
		ТекстОшибки = СвойствоСтруктуры(Результат, "Ошибка", "");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ТекстОшибки) Тогда
		СервисКриптографииDSSСлужебный.ПротоколОшибкиПриВызове(ТекстОшибки, ВидОперации, Неопределено);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ЗаписатьУзелXML(ЗаписьXML, ИмяУзла, ЗначениеУзла, НеВыгружатьПустые = Ложь)
	
	Если НЕ НеВыгружатьПустые ИЛИ НЕ ПустаяСтрока(ЗначениеУзла) Тогда 
		ЗаписьXML.ЗаписатьНачалоЭлемента(ИмяУзла);
		ЗаписьXML.ЗаписатьТекст(Строка(ЗначениеУзла));
		ЗаписьXML.ЗаписатьКонецЭлемента();
	КонецЕсли;
	
КонецПроцедуры

Процедура ПодготовитьФайл(СодержимоеФайла, ИмяФайла, ВременныйКаталог, ТипФайла = "xml")
	
	Если ТипЗнч(СодержимоеФайла) = Тип("ДвоичныеДанные") Тогда
		СодержимоеФайла.Записать(ВременныйКаталог + ИмяФайла);
		
	ИначеЕсли ТипФайла = "xml" Тогда
		ЗаписьXML = Новый ЗаписьXML;
		ЗаписьXML.ОткрытьФайл(ВременныйКаталог + ИмяФайла, "windows-1251");
		ЗаписьXML.ЗаписатьБезОбработки(СодержимоеФайла);
		ЗаписьXML.Закрыть();
		
	КонецЕсли;	
	
КонецПроцедуры

#КонецОбласти

#КонецЕсли

Связанные материалы