Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
theofidry committed Nov 6, 2023
1 parent 922852c commit b462d63
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 66 deletions.
4 changes: 4 additions & 0 deletions res/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
"stub": {
"description": "The relative file path to the stub file, or the flag to use the default stub.",
"type": ["boolean", "string", "null"]
},
"timestamp": {
"description": "The time at which the PHAR timestamp will be set.",
"type": ["string", "null"]
}
}
}
15 changes: 10 additions & 5 deletions src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,11 +369,16 @@ public function extractTo(string $directory, bool $overwrite = false): void
$this->phar->extractTo($directory, overwrite: $overwrite);
}

public function signWithTimestamps(
DateTimeImmutable $timestamp,
SigningAlgorithm $signingAlgorithm
): void
{
public function sign(
SigningAlgorithm $signingAlgorithm,
?DateTimeImmutable $timestamp = null,
): void {
if (null === $timestamp) {
$this->phar->setSignatureAlgorithm($signingAlgorithm->value);

return;
}

$phar = $this->phar;
$phar->__destruct();
unset($this->phar);
Expand Down
91 changes: 59 additions & 32 deletions src/Configuration/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ final class Configuration
private const REPLACEMENTS_KEY = 'replacements';
private const SHEBANG_KEY = 'shebang';
private const STUB_KEY = 'stub';
private const TIMESTAMP = 'timestamp';

private ?string $mainScriptPath;
private ?string $mainScriptContents;
Expand Down Expand Up @@ -344,6 +345,8 @@ public static function create(?string $file, stdClass $raw): self

$replacements = self::retrieveReplacements($raw, $file, $basePath, $logger);

$timestamp = self::retrieveTimestamp($raw, $logger);

return new self(
$file,
$alias,
Expand Down Expand Up @@ -376,45 +379,47 @@ public static function create(?string $file, stdClass $raw): self
$stubPath,
$isInterceptsFileFunctions,
$isStubGenerated,
$timestamp,
$checkRequirements,
$logger->getWarnings(),
$logger->getRecommendations(),
);
}

/**
* @param string $basePath Utility to private the base path used and be able to retrieve a
* path relative to it (the base path)
* @param array $composerJson The first element is the path to the `composer.json` file as a
* string and the second element its decoded contents as an
* associative array.
* @param array $composerLock The first element is the path to the `composer.lock` file as a
* string and the second element its decoded contents as an
* associative array.
* @param SplFileInfo[] $files List of files
* @param SplFileInfo[] $binaryFiles List of binary files
* @param bool $dumpAutoload Whether the Composer autoloader should be dumped
* @param bool $excludeComposerFiles Whether the Composer files composer.json, composer.lock and
* installed.json should be removed from the PHAR
* @param CompressionAlgorithm $compressionAlgorithm Compression algorithm constant value. See the \Phar class constants
* @param null|int $fileMode File mode in octal form
* @param string $mainScriptPath The main script file path
* @param string $mainScriptContents The processed content of the main script file
* @param MapFile $fileMapper Utility to map the files from outside and inside the PHAR
* @param mixed $metadata The PHAR Metadata
* @param bool $promptForPrivateKey If the user should be prompted for the private key passphrase
* @param array $processedReplacements The processed list of replacement placeholders and their values
* @param null|non-empty-string $shebang The shebang line
* @param SigningAlgorithm $signingAlgorithm The PHAR siging algorithm. See \Phar constants
* @param null|string $stubBannerContents The stub banner comment
* @param null|string $stubBannerPath The path to the stub banner comment file
* @param null|string $stubPath The PHAR stub file path
* @param bool $isInterceptFileFuncs Whether Phar::interceptFileFuncs() should be used
* @param bool $isStubGenerated Whether if the PHAR stub should be generated
* @param bool $checkRequirements Whether the PHAR will check the application requirements before
* running
* @param string[] $warnings
* @param string[] $recommendations
* @param string $basePath Utility to private the base path used and be able to retrieve a
* path relative to it (the base path)
* @param array $composerJson The first element is the path to the `composer.json` file as a
* string and the second element its decoded contents as an
* associative array.
* @param array $composerLock The first element is the path to the `composer.lock` file as a
* string and the second element its decoded contents as an
* associative array.
* @param SplFileInfo[] $files List of files
* @param SplFileInfo[] $binaryFiles List of binary files
* @param bool $dumpAutoload Whether the Composer autoloader should be dumped
* @param bool $excludeComposerFiles Whether the Composer files composer.json, composer.lock and
* installed.json should be removed from the PHAR
* @param CompressionAlgorithm $compressionAlgorithm Compression algorithm constant value. See the \Phar class constants
* @param null|int $fileMode File mode in octal form
* @param string $mainScriptPath The main script file path
* @param string $mainScriptContents The processed content of the main script file
* @param MapFile $fileMapper Utility to map the files from outside and inside the PHAR
* @param mixed $metadata The PHAR Metadata
* @param bool $promptForPrivateKey If the user should be prompted for the private key passphrase
* @param array $processedReplacements The processed list of replacement placeholders and their values
* @param null|non-empty-string $shebang The shebang line
* @param SigningAlgorithm $signingAlgorithm The PHAR siging algorithm. See \Phar constants
* @param null|string $stubBannerContents The stub banner comment
* @param null|string $stubBannerPath The path to the stub banner comment file
* @param null|string $stubPath The PHAR stub file path
* @param bool $isInterceptFileFuncs Whether Phar::interceptFileFuncs() should be used
* @param bool $isStubGenerated Whether if the PHAR stub should be generated
* @param null|DateTimeImmutable $timestamp Timestamp at which the PHAR will be set to.
* @param bool $checkRequirements Whether the PHAR will check the application requirements before
* running
* @param string[] $warnings
* @param string[] $recommendations
*/
private function __construct(
private ?string $file,
Expand Down Expand Up @@ -448,6 +453,7 @@ private function __construct(
private ?string $stubPath,
private bool $isInterceptFileFuncs,
private bool $isStubGenerated,
private ?DateTimeImmutable $timestamp,
private bool $checkRequirements,
private array $warnings,
private array $recommendations,
Expand Down Expand Up @@ -679,6 +685,11 @@ public function isStubGenerated(): bool
return $this->isStubGenerated;
}

public function getTimestamp(): ?DateTimeImmutable
{
return $this->timestamp;
}

/**
* @return string[]
*/
Expand Down Expand Up @@ -2064,6 +2075,22 @@ private static function retrieveReplacements(
return $replacements;
}

private static function retrieveTimestamp(
stdClass $raw,
ConfigurationLogger $logger,
): ?DateTimeImmutable {
self::checkIfDefaultValue($logger, $raw, self::TIMESTAMP);

$timestamp = $raw->{self::TIMESTAMP} ?? null;

return null === $timestamp
? null
: new DateTimeImmutable(
$timestamp,
new DateTimeZone('UTC'),
);
}

private static function retrievePrettyGitPlaceholder(stdClass $raw, ConfigurationLogger $logger): ?string
{
return self::retrievePlaceholder($raw, $logger, self::GIT_KEY);
Expand Down
78 changes: 49 additions & 29 deletions src/Console/Command/Compile.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@
use KevinGH\Box\Console\MessageRenderer;
use KevinGH\Box\MapFile;
use KevinGH\Box\Phar\CompressionAlgorithm;
use KevinGH\Box\Phar\SigningAlgorithm;
use KevinGH\Box\RequirementChecker\DecodedComposerJson;
use KevinGH\Box\RequirementChecker\DecodedComposerLock;
use KevinGH\Box\RequirementChecker\RequirementsDumper;
use KevinGH\Box\StubGenerator;
use Phar;
use RuntimeException;
use Seld\PharUtils\Timestamps;
use stdClass;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\StringInput;
Expand Down Expand Up @@ -73,7 +72,6 @@
use function putenv;
use function Safe\getcwd;
use function sprintf;
use function str_replace;
use function var_export;
use const KevinGH\Box\BOX_ALLOW_XDEBUG;
use const PHP_EOL;
Expand Down Expand Up @@ -248,7 +246,8 @@ private function createPhar(
IO $io,
bool $debug,
): Box {
$box = Box::create($config->getTmpOutputPath());
$tmpOutputPath = $config->getTmpOutputPath();
$box = Box::create($tmpOutputPath);
$composerOrchestrator = new ComposerOrchestrator(
ComposerProcessFactory::create(
$config->getComposerBin(),
Expand Down Expand Up @@ -293,13 +292,10 @@ private function createPhar(
$logger,
);

self::correctTimestamp($box, $logger);
exit;
self::signPhar($config, $box, $tmpOutputPath, $io, $logger);

self::signPhar($config, $box, $config->getTmpOutputPath(), $io, $logger);

if ($config->getTmpOutputPath() !== $config->getOutputPath()) {
FS::rename($config->getTmpOutputPath(), $config->getOutputPath());
if ($tmpOutputPath !== $config->getOutputPath()) {
FS::rename($tmpOutputPath, $config->getOutputPath());
}

return $box;
Expand Down Expand Up @@ -748,20 +744,6 @@ private static function configureCompressionAlgorithm(
}
}

private static function correctTimestamp(Box $box, CompilerLogger $logger): void {
$timestamp = new DateTimeImmutable('2017-10-11 08:58:00+00:00');

$logger->log(
CompilerLogger::QUESTION_MARK_PREFIX,
sprintf(
'Correcting the timestamp to "%s".',
$timestamp->format(DateTimeInterface::ATOM),
),
);

$box->signWithTimestamps($timestamp);
}

private static function signPhar(
Configuration $config,
Box $box,
Expand All @@ -775,19 +757,57 @@ private static function signPhar(
$key = $config->getPrivateKeyPath();

if (null === $key) {
$box->sign($config->getSigningAlgorithm());
self::signPharWithoutPrivateKey(
$box,
$config->getSigningAlgorithm(),
$config->getTimestamp(),
$logger,
);
} else {
self::signPharWithPrivateKey(
$box,
$key,
$config->getPrivateKeyPassphrase(),
$config->promptForPrivateKey(),
$io,
$logger,
);
}
}

return;
private static function signPharWithoutPrivateKey(
Box $box,
SigningAlgorithm $signingAlgorithm,
?DateTimeImmutable $timestamp,
CompilerLogger $logger,
): void {
if (null !== $timestamp) {
$logger->log(
CompilerLogger::QUESTION_MARK_PREFIX,
sprintf(
'Correcting the timestamp to "%s".',
$timestamp->format(DateTimeInterface::ATOM),
),
);
}

$box->sign($signingAlgorithm, $timestamp);
}

private static function signPharWithPrivateKey(
Box $box,
string $key,
?string $passphrase,
bool $prompt,
IO $io,
CompilerLogger $logger,
): void {
$logger->log(
CompilerLogger::QUESTION_MARK_PREFIX,
'Signing using a private key',
);

$passphrase = $config->getPrivateKeyPassphrase();

if ($config->promptForPrivateKey()) {
if ($prompt) {
if (false === $io->isInteractive()) {
throw new RuntimeException(
sprintf(
Expand Down

0 comments on commit b462d63

Please sign in to comment.