Last active
March 3, 2023 11:11
-
-
Save Nerahikada/a1fbb18c6fe4b2e10bb7baa7de9d0710 to your computer and use it in GitHub Desktop.
Temporary virion.php (poggit/poggit#317)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
if(empty($argv[1])) exit("Usage: php $argv[0] <target phar>"); | |
if(!file_exists($argv[1]) || !is_file($argv[1])) exit("File \"$argv[1]\" is not found"); | |
if(ini_get("phar.readonly")) exit("Set phar.readonly to false"); | |
if(!function_exists("yaml_parse_file")) exit("YAML extension is not installed"); | |
if(!file_exists(".poggit.yml")) exit(".poggit.yml is not found, skipped"); | |
file_put_contents("virion.php", file_get_contents("https://gist.githubusercontent.com/Nerahikada/a1fbb18c6fe4b2e10bb7baa7de9d0710/raw/virion.php")); | |
$data = yaml_parse_file(".poggit.yml") ?: ["projects" => [["libs" => []]]]; | |
// TODO: validate .poggit.yml | |
foreach(reset($data["projects"])["libs"] as $lib){ | |
$src = $lib["src"]; $version = $lib["version"] ?? "*"; | |
unset($lib["src"], $lib["version"]); | |
file_put_contents("virion.phar", file_get_contents("https://poggit.pmmp.io/v.dl/$src/$version?" . http_build_query($lib))); | |
(new Phar("virion.phar"))->addFile("virion.php", "virion.php"); | |
system("php -dphar.readonly=0 virion.phar $argv[1]"); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php /** @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection */ | |
/* | |
* Poggit | |
* | |
* Copyright (C) 2016-2018 Poggit | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
namespace poggit\virion; | |
use AssertionError; | |
use InvalidArgumentException; | |
use Phar; | |
use RecursiveDirectoryIterator; | |
use RecursiveIteratorIterator; | |
use RuntimeException; | |
use function file_get_contents; | |
use function is_array; | |
use function json_decode; | |
use function json_encode; | |
use function str_replace; | |
use function stripos; | |
use function strlen; | |
use function strpos; | |
use function substr; | |
use function token_get_all; | |
use function yaml_parse; | |
use const DIRECTORY_SEPARATOR; | |
use const PHP_EOL; | |
use const T_NAMESPACE; | |
use const T_STRING; | |
use const T_WHITESPACE; | |
use const T_NAME_FULLY_QUALIFIED; | |
use const T_NAME_QUALIFIED; | |
const VIRION_BUILDER_VERSION = "1.5.1 (https://gist.github.com/Nerahikada/a1fbb18c6fe4b2e10bb7baa7de9d0710)"; | |
const VIRION_INFECTION_MODE_SYNTAX = 0; | |
const VIRION_INFECTION_MODE_SINGLE = 1; | |
const VIRION_INFECTION_MODE_DOUBLE = 2; | |
echo "Using virion builder: version " . VIRION_BUILDER_VERSION, PHP_EOL; | |
function virion_infect(Phar $virus, Phar $host, string $prefix = "", int $mode = VIRION_INFECTION_MODE_SYNTAX, &$hostChanges = 0, &$viralChanges = 0): int { | |
if(!isset($virus["virion.yml"])) { | |
throw new RuntimeException("virion.yml not found, could not activate virion", 2); | |
} | |
$virionYml = yaml_parse(file_get_contents($virus["virion.yml"])); | |
if(!is_array($virionYml)) { | |
throw new RuntimeException("Corrupted virion.yml, could not activate virion", 2); | |
} | |
$srcNamespacePrefix = ""; | |
if(isset($host["plugin.yml"])) { | |
$hostYml = yaml_parse(file_get_contents($host["plugin.yml"])); | |
if(!is_array($hostYml)) { | |
throw new RuntimeException("Corrupted plugin.yml in host plugin, could not inject virion", 2); | |
} | |
$host["plugin.yml"] = yaml_emit($hostYml); | |
$srcNamespacePrefix = str_replace("\\", "/", $hostYml["src-namespace-prefix"] ?? ""); | |
} | |
$infectionLog = isset($host["virus-infections.json"]) ? json_decode(file_get_contents($host["virus-infections.json"]), true) : []; | |
$genus = $virionYml["name"]; | |
$antigen = $virionYml["antigen"]; | |
foreach($infectionLog as $old) { | |
if($old["antigen"] === $antigen) { | |
echo "[!] Target already infected by this virion, aborting\n"; | |
return 3; | |
} | |
} | |
$antibody = $prefix . $antigen; | |
$realAntibody = ($srcNamespacePrefix ? str_replace("/", "\\", $srcNamespacePrefix) . "\\" : "") . $antibody; | |
$infectionLog[$antibody] = $virionYml; | |
echo "Using antibody $antibody for virion $genus ({$antigen})\n"; | |
$hostPharPath = "phar://" . str_replace(DIRECTORY_SEPARATOR, "/", $host->getPath()); | |
$hostChanges = 0; | |
//Replace all virion namespace references with antibody(injected)namespace references. | |
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($hostPharPath)) as $name => $chromosome) { | |
if($chromosome->isDir()) continue; | |
if($chromosome->getExtension() !== "php") continue; | |
$rel = cut_prefix($name, $hostPharPath); | |
$data = change_dna(file_get_contents($name), $antigen, $realAntibody, $mode, $hostChanges); | |
if($data !== "") $host[$rel] = $data; | |
} | |
$restriction = "src/" . str_replace("\\", "/", $antigen) . "/"; // restriction enzyme ^_^ | |
$ligase = str_replace("\\", "/", $antibody) . "/"; | |
if($srcNamespacePrefix !== "" and str_starts_with($ligase, $srcNamespacePrefix)){ | |
$ligase = cut_prefix($ligase, $srcNamespacePrefix."/"); | |
} | |
$ligase = "src/" . $ligase; | |
$viralChanges = 0; | |
foreach(new RecursiveIteratorIterator($virus) as $name => $genome) { | |
if($genome->isDir()) continue; | |
$rel = cut_prefix($name, "phar://" . str_replace(DIRECTORY_SEPARATOR, "/", $virus->getPath()) . "/"); | |
if(strpos($rel, "resources/") === 0) { | |
$host[$rel] = file_get_contents($name); | |
} elseif(strpos($rel, "src/") === 0) { | |
if(strpos($rel, $restriction) !== 0) { | |
echo "Warning: file $rel in virion is not under the antigen $antigen ($restriction)\n"; | |
$newRel = $rel; | |
} else { | |
$newRel = $ligase . cut_prefix($rel, $restriction); | |
} | |
$data = change_dna(file_get_contents($name), $antigen, $realAntibody, $mode, $viralChanges); // it's actually RNA | |
$host[$newRel] = $data; | |
} | |
} | |
$host["virus-infections.json"] = json_encode($infectionLog); | |
return 0; | |
} | |
function cut_prefix(string $string, string $prefix): string { | |
if(strpos($string, $prefix) !== 0) throw new AssertionError("\$string does not start with \$prefix:\n$string\n$prefix"); | |
return substr($string, strlen($prefix)); | |
} | |
function change_dna(string $chromosome, string $antigen, string $antibody, $mode, &$count = 0): string { | |
switch($mode) { | |
case VIRION_INFECTION_MODE_SYNTAX: | |
$tokens = token_get_all($chromosome); | |
$tokens[] = ""; // should not be valid though | |
foreach($tokens as $offset => $token) { | |
if(!is_array($token) or $token[0] !== T_WHITESPACE) { | |
/** @noinspection IssetArgumentExistenceInspection */ | |
list($id, $str, $line) = is_array($token) ? $token : [-1, $token, $line ?? 1]; | |
//namespace test; is a T_STRING whereas namespace test\test; is not. | |
if(isset($init, $prefixToken) and $id === T_STRING){ | |
if($str === $antigen) { // case-sensitive! | |
$tokens[$offset][1] = $antibody . substr($str, strlen($antigen)); | |
++$count; | |
} elseif(stripos($str, $antigen) === 0) { | |
echo "\x1b[38;5;227m\n[WARNING] Not replacing FQN $str case-insensitively.\n\x1b[m"; | |
} | |
unset($init, $prefixToken); | |
} else { | |
if($id === T_NAMESPACE) { | |
$init = $offset; | |
$prefixToken = $id; | |
} elseif($id === T_NAME_QUALIFIED) { | |
if(($str[strlen($antigen)]??"\\") === "\\") { | |
if(strpos($str, $antigen) === 0) { // case-sensitive! | |
$tokens[$offset][1] = $antibody . substr($str, strlen($antigen)); | |
++$count; | |
} elseif(stripos($str, $antigen) === 0) { | |
echo "\x1b[38;5;227m\n[WARNING] Not replacing FQN $str case-insensitively.\n\x1b[m"; | |
} | |
} | |
unset($init, $prefixToken); | |
} elseif($id === T_NAME_FULLY_QUALIFIED){ | |
if(strpos($str, "\\" . $antigen . "\\") === 0) { // case-sensitive! | |
$tokens[$offset][1] = "\\" . $antibody . substr($str, strlen($antigen)+1); | |
++$count; | |
} elseif(stripos($str, "\\" . $antigen . "\\") === 0) { | |
echo "\x1b[38;5;227m\n[WARNING] Not replacing FQN $str case-insensitively.\n\x1b[m"; | |
} | |
unset($init, $prefixToken); | |
} | |
} | |
} | |
} | |
$ret = ""; | |
foreach($tokens as $token) { | |
$ret .= is_array($token) ? $token[1] : $token; | |
} | |
break; | |
case VIRION_INFECTION_MODE_SINGLE: | |
$ret = str_replace($antigen, $antibody, $chromosome, $subCount); | |
$count += $subCount; | |
break; | |
case VIRION_INFECTION_MODE_DOUBLE: | |
$ret = str_replace( | |
[$antigen, str_replace("\\", "\\\\", $antigen)], | |
[$antibody, str_replace("\\", "\\\\", $antibody)], | |
$chromosome, $subCount | |
); | |
$count += $subCount; | |
break; | |
default: | |
throw new InvalidArgumentException("Unknown mode: $mode"); | |
} | |
return $ret; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment