# Регистрация изменений клиента F7cloud для работы с кастомным App Store Все изменения внесены для совместимости с кастомным appstore без полагания на формат и поведение только официального store. Каждое изменение задокументировано для учёта и аудита. --- ## 1. `lib/private/App/AppStore/Fetcher/AppFetcher.php` **Цель:** Исключить падение при отсутствии или неверном формате поля `releases` у приложения (кастомный appstore может отдавать не все поля). **Изменение:** Перед циклом по `$app['releases']` добавлена проверка: если у элемента массива приложений нет ключа `releases` или значение не является массивом, приложение пропускается (для него выставляется пустой элемент и выполняется `continue`). **Фрагмент кода (после изменения):** ```php foreach ($response['data'] as $dataKey => $app) { $releases = []; // Skip apps without valid releases (e.g. custom appstore may omit or use different structure) if (!isset($app['releases']) || !is_array($app['releases'])) { $response['data'][$dataKey] = []; continue; } // Filter all compatible releases foreach ($app['releases'] as $release) { ``` **Регистрация:** изменение в методе `fetch()`, класс `OC\App\AppStore\Fetcher\AppFetcher`. --- ## 2. `lib/private/App/AppStore/Fetcher/Fetcher.php` **Цель:** Корректно обрабатывать оба варианта ответа API appstore: массив приложений в корне JSON `[...]` и обёртку `{"data": [...]}`. **Изменение:** В методе `fetch()` после установки `$responseJson['data']` из тела ответа добавлена нормализация: если декодированный JSON — массив с ключом `data` и значением-массивом, в `$responseJson['data']` подставляется этот внутренний массив; если декодированное значение не массив — `$responseJson['data']` устанавливается в `[]`. **Фрагмент кода (после изменения):** ```php // Normalize: support both root array [...] and wrapped {"data": [...]} from custom appstore $decoded = $responseJson['data']; if (is_array($decoded) && isset($decoded['data']) && is_array($decoded['data'])) { $responseJson['data'] = $decoded['data']; } elseif (!is_array($decoded)) { $responseJson['data'] = []; } ``` **Регистрация:** изменение в методе `fetch()`, класс `OC\App\AppStore\Fetcher\Fetcher`. --- ## 3. `lib/private/Installer.php` **Цель:** При использовании кастомного appstore дать возможность указывать свои CA и CRL для проверки подписей приложений. **Изменение:** В методе `downloadApp()` перед загрузкой корневого сертификата и CRL добавлена проверка: если в конфиге задан кастомный URL appstore (`appstoreurl` ≠ `https://apps.f7cloud.com/api/v1`) и заданы пути к файлам CA и CRL (`appstore_ca_path`, `appstore_crl_path`) и оба файла существуют, используются они; иначе — стандартные пути `resources/codesigning/root.crt` и `resources/codesigning/root.crl`. **Новые параметры конфигурации (config.php):** | Ключ | Тип | Описание | |----------------------|--------|----------| | `appstore_ca_path` | string | Абсолютный путь к файлу CA (PEM) для проверки сертификатов приложений из кастомного appstore. Учитывается только при кастомном `appstoreurl`. | | `appstore_crl_path` | string | Абсолютный путь к файлу CRL для проверки отзыва сертификатов. Учитывается только при кастомном `appstoreurl`. | Оба параметра должны быть заданы и указывать на существующие файлы, иначе используются встроенные CA/CRL. **Регистрация:** изменение в методе `downloadApp()`, класс `OC\Installer`. --- ## 4. `core/Command/App/Install.php` **Цель:** При ошибке установки приложения через `occ app:install` выводить полезную информацию, если сообщение исключения пустое. **Изменение:** В блоке `catch (\Exception $e)` перед выводом сообщения проверяется, не пусто ли `$e->getMessage()` (в т.ч. строка `'0'`). Если пусто — в вывод подставляется строка вида `ИмяКласса in /path/to/file.php:NN`. **Фрагмент кода (после изменения):** ```php } catch (\Exception $e) { $msg = $e->getMessage(); if ($msg === '' || $msg === '0') { $msg = get_class($e) . ' in ' . $e->getFile() . ':' . $e->getLine(); } $output->writeln('Error: ' . $msg); return 1; } ``` **Регистрация:** изменение в методе `execute()`, класс `OC\Core\Command\App\Install`. --- ## 5. URL appstore по умолчанию: `appstore.f7cloud.ru` **Цель:** Использовать `https://appstore.f7cloud.ru/api/v1` как appstore по умолчанию, без прописывания в `config.php`. **Изменения:** - **`lib/private/App/AppStore/Fetcher/Fetcher.php`** - Константа `APP_STORE_URL` изменена с `https://apps.f7cloud.com/api/v1` на `https://appstore.f7cloud.ru/api/v1`. - В `getEndpoint()` fallback для `appstoreurl` заменён на `self::APP_STORE_URL` (вместо захардкоженной строки). - **`lib/private/Installer.php`** - Локальная переменная `$defaultAppStoreUrl` в `downloadApp()` изменена с `https://apps.f7cloud.com/api/v1` на `https://appstore.f7cloud.ru/api/v1` (используется для решения, применять ли кастомные CA/CRL). **Регистрация:** константа и fallback в `OC\App\AppStore\Fetcher\Fetcher`; переменная в `OC\Installer::downloadApp()`. Переопределить URL по-прежнему можно через `config.php`: `'appstoreurl' => 'https://...'`. --- ## 6. Брендинг версии: f7cloud 1.0.0 **Цель:** Отображать продукт как f7cloud 1.0.0 и сохранить совместимость проверок версий приложений (min/max-version). **Изменения:** - **`version.php`** - **OC_VersionString** — `'f7cloud 1.0.0'` (отображается в интерфейсе и в `occ --version`). - **$vendor** — `'f7cloud'`. - **OC_Version** — `[1,0,0,0]` (числовая версия 1.0.0 на клиенте). - В **OC_VersionCanBeUpgradedFrom** добавлен `'f7cloud' => array('1.0' => true)`. - **`lib/private/legacy/OC_Defaults.php`** - **defaultEntity**, **defaultName**, **defaultTitle** и **defaultProductName** изменены с `'F7cloud'` на `'f7cloud'` — название продукта в интерфейсе, заголовках и подвалах. **Регистрация:** `version.php` (корень); класс `OC_Defaults` в `lib/private/legacy/OC_Defaults.php`. Тема и `config.php` по-прежнему могут переопределять название продукта (например, через тему с методом `getProductName()`). --- ## 7. Отключение проверки сертификатов и подписей **Цель:** Отключить проверку сертификатов и подписей для приложений и обновлений core, удалить сертификаты. **Изменения:** - **`lib/private/Installer.php`** - Отключена проверка сертификата приложения (загрузка CA, проверка CRL, валидация подписи CA, проверка CN). - Отключена проверка подписи скачанного архива приложения (`openssl_verify`). - Приложения устанавливаются без проверки сертификатов и подписей. - **`updater/index.php`** - Метод `verifyIntegrity()` отключён — проверка подписи обновлений core не выполняется. Метод сразу возвращает управление. - **`lib/private/IntegrityCheck/Checker.php`** - Метод `verify()` отключён — проверка целостности кода (валидация сертификатов и подписей файлов) не выполняется. Метод возвращает пустой массив. - **`resources/codesigning/`** - Удалены файлы сертификатов: `root.crt`, `core.crt`, `root.crl`. - Оставлены только license файлы (`.license`). **Регистрация:** изменения в `OC\Installer::downloadApp()`, `Updater::verifyIntegrity()`, `OC\IntegrityCheck\Checker::verify()`; удаление файлов в `resources/codesigning/`. **Внимание:** После этих изменений приложения и обновления устанавливаются без проверки подлинности. Используйте только доверенные источники. --- ## 8. Числовая версия 1.0.0 у клиента и приложений **Цель:** Использовать числовую версию 1.0.0 на клиенте и привести все приложения к совместимости с 1.x. **Изменения:** - **`version.php`** - **OC_Version** установлен в `array(1,0,0,0)` — числовая версия платформы 1.0.0 (для DependencyAnalyzer, AppFetcher, config). - **Приложения (`apps/*/appinfo/info.xml`)** - Во всех приложениях зависимости f7cloud приведены к диапазону 1.x: `min-version="1"` и `max-version="2"` (вместо min/max 28–34 или 32). - Так платформа 1.0.0 проходит проверку совместимости (1.0.0 ≥ 1 и 1.0.0 ≤ 2). **Регистрация:** `version.php`; все `appinfo/info.xml` с блоком ``. --- ## Существующее поведение Fetcher (без изменений в этом реестре) В `lib/private/App/AppStore/Fetcher/Fetcher.php` в методе `get()` уже присутствует: - Обработка ошибок чтения кэша: при любой исключении при чтении/разборе файла кэша выполняется попытка получить новый файл и выполнить запрос к appstore (поведение как при отсутствии кэша). - После успешного `putContent()` возвращаются данные из памяти (`$responseJson['data']`), а не из перечитанного файла, чтобы избежать проблем с только что записанным кэшем (например, в appdata). Эти части кода в данном реестре не менялись и приведены только для полноты картины работы с кастомным appstore. --- ## Краткая сводка файлов | Файл | Изменение | |------|------------| | `lib/private/App/AppStore/Fetcher/AppFetcher.php` | Защитная проверка `releases` перед циклом | | `lib/private/App/AppStore/Fetcher/Fetcher.php` | Нормализация формата ответа; дефолтный URL appstore `appstore.f7cloud.ru` | | `lib/private/Installer.php` | Опциональные CA/CRL для кастомного appstore; дефолтный URL appstore для проверки CA/CRL | | `core/Command/App/Install.php` | Вывод класса и file:line при пустом сообщении исключения | | `version.php` | Строка и числовая версия `f7cloud 1.0.0` (OC_Version [1,0,0,0]) | | `apps/*/appinfo/info.xml` | Зависимости f7cloud: min-version="1" max-version="2" для совместимости с 1.0.0 | | `lib/private/legacy/OC_Defaults.php` | Название продукта и entity/name/title: f7cloud | | `lib/private/Installer.php` | Проверка сертификатов и подписей при установке приложений отключена | | `updater/index.php` | Проверка сертификатов при обновлении core отключена | | `lib/private/IntegrityCheck/Checker.php` | Проверка целостности кода (сертификаты) отключена | | `resources/codesigning/` | Сертификаты удалены (оставлены только license файлы) | Дата регистрации изменений: 2025-02-02.