fix(admin): route multi-megabyte sets to SFTP before shell escaping
deploy-preland / deploy zoomstage.online (push) Successful in 1m3s

This commit is contained in:
Panfilov Konstantin committed 2026-10-25 22:14:15 +03:00
1 parent 6ec813bc99
commit 4fc4fd8162
2 files changed
+27 -3

No files matched your search

+7 -3
View File
@@ -29,11 +29,15 @@ final class Transport
$ssh=$this->connect();$code=file_get_contents(__DIR__.'/Remote.php');$code=preg_replace('/^<\?php\s*/','',$code);
// Сжат только доверенный helper из поставки; payload остаётся JSON-данными.
$entry="\necho json_encode(\\PrelandAdmin\\Remote::execute(json_decode(base64_decode(\$argv[1]),true,64,JSON_THROW_ON_ERROR)),JSON_THROW_ON_ERROR);";
$command=self::inlineCommand($code,$entry,base64_encode(json_encode($payload,JSON_THROW_ON_ERROR)));
$jsonPayload=json_encode($payload,JSON_THROW_ON_ERROR);
// Размер base64 проверяется ДО inlineCommand/escapeshellarg: для ZIP PHP
// завершает процесс при аргументе >2 МиБ раньше переключения на inbox.
$argumentLength=4*intdiv(strlen($jsonPayload)+2,3);
$command=$argumentLength>self::COMMAND_LIMIT?null:self::inlineCommand($code,$entry,base64_encode($jsonPayload));
$inbox=null;$sftp=null;
try {
// Большие наборы доставляются SFTP в приватный inbox: argv/ARG_MAX не используется.
if(strlen($command)>self::COMMAND_LIMIT) {
if($command===null||strlen($command)>self::COMMAND_LIMIT) {
if(($payload['op']??null)==='test')throw new Problem('SSH bootstrap превышает безопасный предел команды; сократите helper или путь подключения.');
$parent=dirname($this->target['root']);$private=$parent.'/.preland-admin-'.substr(hash('sha256',$this->target['root']),0,16);
$candidate=$private.'/inbox-'.bin2hex(random_bytes(16));
@@ -41,7 +45,7 @@ final class Transport
// не должен бесконечно пытаться доставить сам себя через inbox.
$command=self::inboxCommand($code,$candidate);
$this->call(['op'=>'test']);$sftp=$this->sftp();$inbox=$candidate;
if(!$sftp->put($inbox,json_encode($payload,JSON_THROW_ON_ERROR))||!$sftp->chmod(0600,$inbox))throw new Problem('Не удалось доставить подготовленный набор.');
if(!$sftp->put($inbox,$jsonPayload)||!$sftp->chmod(0600,$inbox))throw new Problem('Не удалось доставить подготовленный набор.');
}
$timeout=max(1,min(120,(int)(getenv('ADMIN_TRANSPORT_TIMEOUT')?:60)));$ssh->setTimeout($timeout);
$output=$ssh->exec($command);$result=is_string($output)?json_decode($output,true):null;