diff --git a/packagedef b/packagedef index 8d9a932..b05af5d 100644 --- a/packagedef +++ b/packagedef @@ -1,5 +1,5 @@ Описание.Имя("yard") - .Версия("1.9.9") + .Версия("1.10.9") .ВерсияСреды("1.6") .ЗависитОт("logos") .ЗависитОт("asserts") @@ -10,6 +10,7 @@ .ЗависитОт("tempfiles") .ЗависитОт("fs") .ЗависитОт("1commands") + .ЗависитОт("1connector") .РазработкаЗависитОт("1testrunner") .РазработкаЗависитОт("1bdd") .ВключитьФайл("packagedef") diff --git "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\320\276\320\267\321\200\320\265\320\262\320\260\321\202\320\265\320\273\321\214\320\241\320\260\320\271\321\202\320\2601\320\241.os" "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\320\276\320\267\321\200\320\265\320\262\320\260\321\202\320\265\320\273\321\214\320\241\320\260\320\271\321\202\320\2601\320\241.os" index 57b217a..dd80e59 100644 --- "a/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\320\276\320\267\321\200\320\265\320\262\320\260\321\202\320\265\320\273\321\214\320\241\320\260\320\271\321\202\320\2601\320\241.os" +++ "b/src/\320\232\320\273\320\260\321\201\321\201\321\213/\320\236\320\261\320\276\320\267\321\200\320\265\320\262\320\260\321\202\320\265\320\273\321\214\320\241\320\260\320\271\321\202\320\2601\320\241.os" @@ -12,16 +12,16 @@ // // ---------------------------------------------------------- -#Использовать asserts +#Использовать 1connector #Область ПеременныеМодуля -Перем Лог; // Объект - объект записи лога приложения +Перем Лог; // Объект - объект записи лога приложения -Перем ИмяПользователя; // Строка - имя пользователя сервиса загрузки релизов -Перем ПарольПользователя; // Строка - пароль пользователя сервиса загрузки релизов -Перем ИдСеанса; // Строка - идентификатор сеанса сервиса загрузки релизов -Перем ВремяОжиданияОтвета; // Число - время ожидания ответа от внешнего ресурса (HTTP) в секундах +Перем ИмяПользователя; // Строка - имя пользователя сервиса загрузки релизов +Перем ПарольПользователя; // Строка - пароль пользователя сервиса загрузки релизов +Перем ВремяОжиданияОтвета; // Число - время ожидания ответа от внешнего ресурса (HTTP) в секундах +Перем Сессия; // Сессия - Сессия в рамках которой происходят все взаимодействия с сайтом 1с. #КонецОбласти // ПеременныеМодуля @@ -82,7 +82,7 @@ Знач ПолучатьБетаВерсии = Ложь) Экспорт СтраницаКонфигураций = ПолучитьСтраницуСайта(ПараметрыПриложения.СервисРелизов(), - ПараметрыПриложения.СтраницаСпискаРелизов()); + ПараметрыПриложения.СтраницаСпискаРелизов()); Служебный.ОчиститьТекстСтраницыHTML(СтраницаКонфигураций); @@ -100,7 +100,7 @@ ТекстСтрокиКонфигурации = ТекСтрокаКонфигурации.Группы[0].Значение; НайденныеОписания = Служебный.НайтиСовпаденияВТексте(ТекстСтрокиКонфигурации, - ПараметрыПриложения.ШаблонПоискаКонфигураций()); + ПараметрыПриложения.ШаблонПоискаКонфигураций()); Если НайденныеОписания.Количество() = 0 ИЛИ НайденныеОписания[0].Группы.Количество() < 3 Тогда @@ -394,201 +394,100 @@ // ПутьКФайлуДляСохранения - Строка - путь к файлу для сохранения // Процедура ЗагрузитьФайл(АдресИсточника, Знач ПутьКФайлуДляСохранения) Экспорт - - СтруктураАдреса = СтруктураURI(АдресИсточника); - Сервер = СтрШаблон("%1://%2", СтруктураАдреса.Схема, СтруктураАдреса.Хост); - ИдСеансаЗагрузки = Авторизация(Сервер, ИмяПользователя, ПарольПользователя, СтруктураАдреса.ПутьНаСервере); - - Соединение = Новый HTTPСоединение(Сервер, , , , , ВремяОжиданияОтвета()); - Соединение.РазрешитьАвтоматическоеПеренаправление = Истина; - - Запрос = ЗапросКСайту(АдресИсточника); - Запрос.Заголовки.Вставить("Cookie", ИдСеансаЗагрузки); - Лог.Отладка("Загрузка файла: Начало загрузки файла по адресу ""%1""", АдресИсточника); - - Ответ = Соединение.Получить(Запрос, ПутьКФайлуДляСохранения); - - Лог.Отладка("Загрузка файла: Загружен файл ""%1""", ПутьКФайлуДляСохранения); - -КонецПроцедуры // ЗагрузитьФайл() - -// Функция - выполняет авторизацию на сайте 1С и возвращает идентификатор сеанса -// -// Параметры: -// Сервер - Строка - адрес сервера -// Имя - Строка - имя пользователя -// Пароль - Строка - пароль пользователя -// АдресРесурса - Строка - расположение ресурса на сервере -// -// Возвращаемое значение: -// Строка - текст полученной страницы -// -Функция Авторизация(Знач Сервер, Знач Имя, Знач Пароль, Знач АдресРесурса = "") Экспорт - - ИмяПользователя = Имя; - ПарольПользователя = Пароль; - - КодПереадресации = 302; - КодОшибкиАвторизации = 401; - - СоединениеРегистрации = Новый HTTPСоединение(ПараметрыПриложения.СервисАвторизации(), , , , , ВремяОжиданияОтвета()); - СоединениеРегистрации.РазрешитьАвтоматическоеПеренаправление = Ложь; - - СоединениеЦелевое = Новый HTTPСоединение(Сервер, , , , , ВремяОжиданияОтвета()); - СоединениеЦелевое.РазрешитьАвтоматическоеПеренаправление = Ложь; - - // Запрос 1 - ЗапросПолучение = ЗапросКСайту(); - ЗапросПолучение.АдресРесурса = АдресРесурса; - - // Ответ 1 - переадресация на страницу регистрации - ОтветПереадресация = СоединениеЦелевое.Получить(ЗапросПолучение); - НовыйИдСеанса = ПолучитьЗначениеЗаголовка("set-cookie", ОтветПереадресация.Заголовки); - НовыйИдСеанса = Сред(НовыйИдСеанса, Найти(НовыйИдСеанса, "SESSION=")); - НовыйИдСеанса = Лев(НовыйИдСеанса, Найти(НовыйИдСеанса, ";") - 1); - - Лог.Отладка("Авторизация: Получен ответ от ресурса ""%1%2"", переадресация -> ""%3""", - Сервер, - ЗапросПолучение.АдресРесурса, - ПолучитьЗначениеЗаголовка("location", ОтветПереадресация.Заголовки)); - - // Запрос 2 - переходим на страницу регистрации - ЗапросПолучение.АдресРесурса = СтрЗаменить(ПолучитьЗначениеЗаголовка("location", ОтветПереадресация.Заголовки), - ПараметрыПриложения.СервисАвторизации(), - ""); - - // Ответ 2 - получение строки регистрации - ОтветРегистрация = СоединениеРегистрации.Получить(ЗапросПолучение); - ТелоОтвета = ОтветРегистрация.ПолучитьТелоКакСтроку(); - СтрокаРегистрации = ПолучитьСтрокуРегистрации(ТелоОтвета, ИмяПользователя, ПарольПользователя); - - Лог.Отладка("Авторизация: Получена строка регистрации от ресурса ""%1%2"": ""%3""", - ПараметрыПриложения.СервисАвторизации(), - ЗапросПолучение.АдресРесурса, - СтрокаРегистрации); - - // Запрос 3 - выполнение регистрации - ЗапросОбработка = ЗапросКСайту(ПараметрыПриложения.СтраницаАвторизации()); - ЗапросОбработка.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded"); - ЗапросОбработка.Заголовки.Вставить("Cookie", НовыйИдСеанса + "; i18next=ru-RU"); - ЗапросОбработка.УстановитьТелоИзСтроки(СтрокаРегистрации); - - // Ответ 3 - проверка успешности регистрации - ОтветПроверка = СоединениеРегистрации.ОтправитьДляОбработки(ЗапросОбработка); - - СообщениеОбОшибке = "Код переадресации не соответствует ожидаемому!"; - - Если ОтветПроверка.КодСостояния = КодОшибкиАвторизации Тогда - СообщениеОбОшибке = СтрШаблон("Ошибка авторизации на сайте %1/%2 (пользователь: %3)", - ПараметрыПриложения.СервисАвторизации(), - ЗапросОбработка.АдресРесурса, - Имя); - КонецЕсли; - - Утверждения.ПроверитьРавенство(ОтветПроверка.КодСостояния, - КодПереадресации, - СообщениеОбОшибке); - - Лог.Отладка("Авторизация: Получен ответ от ресурса ""%1%2"", переадресация -> ""%3""", - ПараметрыПриложения.СервисАвторизации(), - ЗапросОбработка.АдресРесурса, - ПолучитьЗначениеЗаголовка("location", ОтветПроверка.Заголовки)); - - // Запрос 4 - переход на целевую страницу - ЗапросПолучение.АдресРесурса = СтрЗаменить(ПолучитьЗначениеЗаголовка("location", ОтветПроверка.Заголовки), Сервер, ""); - ЗапросПолучение.Заголовки.Вставить("Cookie", НовыйИдСеанса); - СоединениеЦелевое.Получить(ЗапросПолучение); + Ответ = ВыполнитьЗапросНаСайт(АдресИсточника, "", ПутьКФайлуДляСохранения); - Лог.Отладка("Авторизация: Получен ответ от ресурса ""%1%2"", ID сеанса: ""%3""", - Сервер, - ЗапросПолучение.АдресРесурса, - НовыйИдСеанса); + Если НЕ СтрНайти(Ответ.Заголовки.Получить("Content-Type"), "application/octet-stream;") Тогда + ВызватьИсключение СтрШаблон("КодВозврата: %1 + |ТекстОтвета: %2", Ответ.КодСостояния, Ответ.Текст()); + КонецЕсли; - Возврат НовыйИдСеанса; + Лог.Отладка("Загрузка файла: Загружен файл ""%1""", ПутьКФайлуДляСохранения); -КонецФункции // Авторизация() +КонецПроцедуры // ЗагрузитьФайл() #КонецОбласти // ПрограммныйИнтерфейс #Область РаботаСсайтом -// Функция - получает строку регистрации на основе данных страницы авторизации -// -// Параметры: -// Текст - Строка - текст страницы авторизации -// Имя - Строка - имя пользователя -// Пароль - Строка - пароль пользователя -// -// Возвращаемое значение: -// Строка - строка регистрации на сайте -// -Функция ПолучитьСтрокуРегистрации(Знач Текст, Знач Имя, Знач Пароль) - - Совпадения = Служебный.НайтиСовпаденияВТексте(Текст, ПараметрыПриложения.ШаблонПоискаСтрокиРегистрации()); - - Токен = ""; - Если Совпадения.Количество() > 0 Тогда - Токен = Совпадения[0].Группы[1].Значение; - КонецЕсли; - - Возврат СтрШаблон(ПараметрыПриложения.ШаблонСтрокиРегистрации(), Имя, Пароль, Токен); - -КонецФункции // ПолучитьСтрокуРегистрации() - // Функция - получает страницу с сайта // // Параметры: // Сервер - Строка - адрес сервера // АдресРесурса - Строка - расположение ресурса на сервере -// АвтоматическоеПеренаправление - Булево - Истина - будет выполняться автоматическое перенаправление -// при соответствующем ответе сервера -// Ложь - перенаправление выполняться не будет // // Возвращаемое значение: // Строка - текст полученной страницы // -Функция ПолучитьСтраницуСайта(Знач Сервер, Знач АдресРесурса, Знач АвтоматическоеПеренаправление = Ложь) +Функция ПолучитьСтраницуСайта(Знач Сервер, Знач АдресРесурса) - Соединение = Новый HTTPСоединение(Сервер, , , , , ВремяОжиданияОтвета()); - Соединение.РазрешитьАвтоматическоеПеренаправление = АвтоматическоеПеренаправление; - - Запрос = ЗапросКСайту(АдресРесурса); - Запрос.Заголовки.Вставить("Cookie", ИдСеанса); + Ответ = ВыполнитьЗапросНаСайт(Сервер, АдресРесурса); - Ответ = Соединение.Получить(Запрос); - Лог.Отладка("Получена страница сайта ""%1%2""", Сервер, АдресРесурса); - - Возврат Ответ.ПолучитьТелоКакСтроку(); - + + Возврат Ответ.Текст(); + КонецФункции // ПолучитьСтраницуСайта() -#КонецОбласти // РаботаСсайтом +Функция ВыполнитьЗапросНаСайт(Знач Сервер, Знач АдресРесурса, Знач ПутьКФайлуДляСохранения = "") + ДопПараметры = Новый Структура("ИмяВыходногоФайла, Таймаут", ПутьКФайлуДляСохранения, ВремяОжиданияОтвета()); -#Область СлужебныеПроцедурыИФункции + Ответ = Сессия.ВызватьМетод("GET", СтрШаблон("%1%2", Сервер, АдресРесурса), ДопПараметры); + + Если ТребуетсяАвторизация(Ответ) Тогда + Лог.Отладка("Авторизация: Получен ответ от ресурса ""%1%2"", Необходима авторизация", + Сервер, + АдресРесурса); -// Функция - создает и возвращает HTTP-запрос со стандартными заголовками + Ответ = Авторизация(Ответ); + КонецЕсли; + + Возврат Ответ; +КонецФункции + +// Функция - выполняет авторизацию на сайте 1С +// и выполняет запрос который предшествовал попаданию на страницу авторизации. // // Параметры: -// АдресРесурса - Строка - адрес ресурса на сайте +// Ответ - ПодготовленныйОтвет - Ответ предыдущего запроса, +// для выполнения которого потребовалась авторизация // // Возвращаемое значение: -// HTTPЗапрос - HTTP-запрос со стандартными заголовками +// ПодготовленныйОтвет - Ответ на запрос который был перенаправлен на авторизацию // -Функция ЗапросКСайту(АдресРесурса = "") - - Запрос = Новый HTTPЗапрос; - Запрос.Заголовки.Вставить("User-Agent", "oscript"); - Запрос.Заголовки.Вставить("Connection", "keep-alive"); - Запрос.АдресРесурса = АдресРесурса; +Функция Авторизация(Знач Ответ) + + КодОшибкиАвторизации = 401; + + Execution = ИзвлечьExecution(Ответ.Текст()); + + + Данные = Новый Структура; + Данные.Вставить("execution", Execution); + Данные.Вставить("username", ИмяПользователя); + Данные.Вставить("password", ПарольПользователя); + Данные.Вставить("_eventId", "submit"); + Данные.Вставить("geolocation", ""); + Данные.Вставить("submit", "Войти"); + Данные.Вставить("rememberMe", "on"); + + Ответ = Сессия.ВызватьМетод("POST", Ответ.URL, Новый Структура("Данные", Данные)); + + Если Ответ.КодСостояния = КодОшибкиАвторизации Тогда + СообщениеОбОшибке = СтрШаблон("Ошибка авторизации на сайте пользователь: %1", + ИмяПользователя); + ВызватьИсключение СообщениеОбОшибке; + КонецЕсли; + + Возврат Ответ; +КонецФункции // Авторизация() - Возврат Запрос; +#КонецОбласти // РаботаСсайтом -КонецФункции // ЗапросКСайту() +#Область СлужебныеПроцедурыИФункции // Функция - выделяет имя файла из полного адреса файла // @@ -677,97 +576,33 @@ КонецФункции // СоответствуетФильтру() -Функция ПолучитьЗначениеЗаголовка(Заголовок, ВсеЗаголовки) - - Для Каждого ТекЗаголовок Из ВсеЗаголовки Цикл - Если НРег(ТекЗаголовок.Ключ) = НРег(Заголовок) Тогда - Возврат ТекЗаголовок.Значение; - КонецЕсли; - КонецЦикла; - - Возврат ""; - -КонецФункции // ПолучитьЗначениеЗаголовка() - -// Функция - разбирает строку URI на составные части и возвращает в виде структуры. -// На основе RFC 3986. -// утащено из https://its.1c.ru/db/metod8dev#content:5574:hdoc, также есть в БСП -// -// Параметры: -// СтрокаURI - Строка - ссылка на ресурс в формате: -// <схема>://<логин>:<пароль>@<хост>:<порт>/<путь>?<параметры>#<якорь>. -// -// Возвращаемое значение: -// Структура - составные части URI согласно формату: -// * Схема - Строка - схема из URI. -// * Логин - Строка - логин из URI. -// * Пароль - Строка - пароль из URI. -// * ИмяСервера - Строка - часть <хост>:<порт> из URI. -// * Хост - Строка - хост из URI. -// * Порт - Строка - порт из URI. -// * ПутьНаСервере - Строка - часть <путь>?<параметры>#<якорь> из URI. -// -Функция СтруктураURI(Знач СтрокаURI) Экспорт - - СтрокаURI = СокрЛП(СтрокаURI); - - // схема - Схема = ""; - Разделитель = "://"; - Позиция = Найти(СтрокаURI, Разделитель); - Если Позиция > 0 Тогда - Схема = НРег(Лев(СтрокаURI, Позиция - 1)); - СтрокаURI = Сред(СтрокаURI, Позиция + СтрДлина(Разделитель)); - КонецЕсли; +Функция ТребуетсяАвторизация(Ответ) + Возврат СтрНачинаетсяС(Ответ.URL, СтрШаблон("%1%2", ПараметрыПриложения.СервисАвторизации(), + ПараметрыПриложения.СтраницаАвторизации())); +КонецФункции - // строка соединения и путь на сервере - СтрокаСоединения = СтрокаURI; - ПутьНаСервере = ""; - Позиция = Найти(СтрокаСоединения, "/"); - Если Позиция > 0 Тогда - ПутьНаСервере = Сред(СтрокаСоединения, Позиция + 1); - СтрокаСоединения = Лев(СтрокаСоединения, Позиция - 1); - КонецЕсли; - - // информация пользователя и имя сервера - СтрокаАвторизации = ""; - ИмяСервера = СтрокаСоединения; - Позиция = Найти(СтрокаСоединения, "@"); - Если Позиция > 0 Тогда - СтрокаАвторизации = Лев(СтрокаСоединения, Позиция - 1); - ИмяСервера = Сред(СтрокаСоединения, Позиция + 1); - КонецЕсли; +Функция ИзвлечьExecution(Текст) + execution = ""; + Совпадения = Служебный.НайтиСовпаденияВТексте(Текст, ПараметрыПриложения.ШаблонПоискаСтрокиРегистрации()); - // логин и пароль - Логин = СтрокаАвторизации; - Пароль = ""; - Позиция = Найти(СтрокаАвторизации, ":"); - Если Позиция > 0 Тогда - Логин = Лев(СтрокаАвторизации, Позиция - 1); - Пароль = Сред(СтрокаАвторизации, Позиция + 1); + Если Совпадения.Количество() > 0 Тогда + execution = Совпадения[0].Группы[1].Значение; КонецЕсли; - // хост и порт - Хост = ИмяСервера; - Порт = ""; - Позиция = Найти(ИмяСервера, ":"); - Если Позиция > 0 Тогда - Хост = Лев(ИмяСервера, Позиция - 1); - Порт = Сред(ИмяСервера, Позиция + 1); + Если НЕ ЗначениеЗаполнено(execution) Тогда + ВызватьИсключение "Авторизация: Ожидали что execution будет заполнен, но это не так!"; КонецЕсли; - Результат = Новый Структура; - Результат.Вставить("Схема", Схема); - Результат.Вставить("Логин", Логин); - Результат.Вставить("Пароль", Пароль); - Результат.Вставить("ИмяСервера", ИмяСервера); - Результат.Вставить("Хост", Хост); - Результат.Вставить("Порт", ?(Порт <> "", Число(Порт), Неопределено)); - Результат.Вставить("ПутьНаСервере", ПутьНаСервере); - - Возврат Результат; - -КонецФункции // СтруктураURI() + Возврат execution; +КонецФункции + + +Процедура ИнициализацияСессии() + Если НЕ ЗначениеЗаполнено(Сессия) Тогда + Лог.Отладка("Инициализирована новая сессия."); + Сессия = Новый Сессия; + КонецЕсли; +КонецПроцедуры // Процедура - сортирует массив описаний версий по датам версий // @@ -807,12 +642,8 @@ ПарольПользователя = Пароль; Лог = ПараметрыПриложения.Лог(); - - ИдСеанса = Авторизация(ПараметрыПриложения.СервисРелизов(), - ИмяПользователя, - ПарольПользователя, - ПараметрыПриложения.СтраницаСпискаРелизов()); - + ИнициализацияСессии(); + КонецПроцедуры // ПриСозданииОбъекта() -#КонецОбласти // Инициализация +#КонецОбласти // Инициализация \ No newline at end of file