Для того чтобы зашифровать данные в пакете давайте сперва изучим как он устроен. В данной статье приведу пример как защитить пакет на примере механизма защиты введенного на сайте-магазине MODStore.PRO. Пример исходных материалов для сборки дополнения вы можете посмотреть здесь на GitLAB.
В механизме сборки распространяемых пакетов (transport) заложена очень гибкая механика. Первичная информация о пакете содержится в манифесте - manifest.php. В нем описаны характеристики пакета-транспорта и перечисляется список носителей - vehicles. В частности именно содержимое vehicle и подлежит шифрованию.
В MODx есть предопределенный набор видов носителей:
У каждого vehicle может быть свой набор обработчиков проверки (validator) и разрешителей (resolver). Они в свою очередь могут быть типов: file, php. Для решение нашей задачи понадобится resolver обоих типов.
Вам подвластно управление почти всяким аспектом построения пакета. Практичнее зашифровать чувствительную информацию - исходные файлы дополнения и описания устанавливаемых объектов. Данные о системных настройках шифровать мало практично, хоть и технически возможно. Мы рассмотрим случай, когда будут шифроваться данные в объекте modCategory и приложенные файлы в резолвер типа file - в нем содержатся все исходники дополнения.
Нам понадобится класс хранителя на основе xPDOObjectVehicle, назовем его EncryptedVehicle.
Класс EncryptVehicle выполняет несколько задач:
Процесс установки выполняется в порядке размещения носителей внутри транспорта. Поэтому чтобы класс был загружен к моменту обработки носителя нужно запустить скрипт прежде чем он будет обработан. При удалении пакета носители обрабатываются в обратной очередности, поэтому скрипт-загрузчик надо так же разместить в самом конце.
Получается следующий порядок носителей и обработчиков:
Теперь что нужно и куда добавить.
Сперва надо получить ключ шифрования. Для авторов расширений в MODx они выдаются бесплатно, нужно при этом указать свой логин и ключ привязанный к сайту.
Переменные MODSTORE_LOGIN и MODSTORE_KEY определите в конфигураторе.
$keyRequester = new KeyRequester($modx, [
KeyRequester::PARAM_USERNAME => MODSTORE_LOGIN,
KeyRequester::PARAM_API_KEY => MODSTORE_KEY, // modstore.pro API
KeyRequester::PARAM_PACKAGE => PKG_NAME_LOWER,
KeyRequester::PARAM_VERSION => PKG_VERSION . '-' . PKG_RELEASE
]);
define('PKG_ENCODE_KEY', $keyRequester->getKey());
Добавим носитель с классом
$builder->package->put(new xPDOFileVehicle, [
'vehicle_class' => xPDOFileVehicle::class,
'object' => [
'source' => $sources['build'] . 'helpers/encryptedvehicle.class.php',
]
]);
Следом добавляем загрузчик класса
$builder->package->put(new xPDOScriptVehicle, [
'vehicle_class' => xPDOScriptVehicle::class,
'object' => [
'source' => $sources['build'] . 'helpers/encryption.php'
]
]);
Затем собираем основной набор объектов и в объекте категории указываем, что класс обработчика будет EncryptedVehicle.
$category = $modx->newObject('modCategory');
$category->set('category', PKG_NAME);
/* create category vehicle */
$attr = array(
xPDOTransport::UNIQUE_KEY => 'category',
xPDOTransport::PRESERVE_KEYS => false,
xPDOTransport::UPDATE_OBJECT => true,
xPDOTransport::RELATED_OBJECTS => true,
'vehicle_class' => EncryptedVehicle::class
);
...
$vehicle = $builder->createVehicle($category, $attr);
/* now pack in resolvers */
$vehicle->resolve('file', array(
'source' => $sources['source_assets'],
'target' => "return MODX_ASSETS_PATH . 'components/';",
));
$vehicle->resolve('file', array(
'source' => $sources['source_core'],
'target' => "return MODX_CORE_PATH . 'components/';",
));
...
$builder->putVehicle($vehicle);
Добавляете нужные носители и в конце еще раз загрузчик класса.
$builder->package->put(new xPDOScriptVehicle, [
'vehicle_class' => xPDOScriptVehicle::class,
'object' => [
'source' => $sources['build'] . 'helpers/encryption.php'
]
]);
Это что касается сборщика транспорта.
Загрузчик класса helpers/encryption.php
<?php
/**
* @var xPDOTransport $transport
*/
if (!class_exists('EncryptedVehicle')) {
$classIndex = 0;
if (!class_exists('xPDOObjectVehicle'))
$transport->xpdo->loadClass('transport.xPDOObjectVehicle', XPDO_CORE_PATH, true, true);
// Store info about encoder in first
$payload = include($transport->path . $transport->signature . '/' . $transport->vehicles[$classIndex]['filename']);
$path = $transport->path . $transport->signature . '/' . $payload['class'] . '/' . $payload['signature'] . '/';
$transport->xpdo->loadClass('EncryptedVehicle', $path, true, true);
}
return true;
Этих изменений достаточно для рас/шифрования внутренней информации внутри vehicle. Чтобы расшифровать файлы нужно их обработать после их установки в систему через обработчик resolver. Он должен быть перечислен после файлового резолвера, который производит копирование файлов в систему.
Резолвер resolve.decode.php надо прописать в конфигуратор и разместить файл в каталог resolvers.
<?php
if ($object->xpdo) {
/** @var modX $modx */
$modx =& $object->xpdo;
switch ($options[xPDOTransport::PACKAGE_ACTION]) {
case xPDOTransport::ACTION_INSTALL:
case xPDOTransport::ACTION_UPGRADE:
if ($options['vehicle_class'] == 'EncryptedVehicle') {
foreach ($options['resolve'] as $idx => $values) {
if ($values['type'] == 'file') {
$fileMeta = $transport->xpdo->fromJSON($values['body'], true);
$fileTarget = eval($fileMeta['target']);
$fileTargetPath = $fileTarget . $fileMeta['name'];
EncryptedVehicle::decodeTree($fileTargetPath);
$modx->log(xPDO::LOG_LEVEL_DEBUG, "Contents decoded: $fileTargetPath");
}
}
}
break;
case xPDOTransport::ACTION_UNINSTALL:
break;
}
}
return true;
Метки: