diff --git a/Makefile b/Makefile
index 0f18b7a..1dd3779 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,3 @@
.phony: phar
phar:
- makephar -c makephar.conf
+ ./makephar -c makephar.conf
diff --git a/bin/bootstrap.php b/bin/bootstrap.php
index b3fbe85..6fefdcc 100644
--- a/bin/bootstrap.php
+++ b/bin/bootstrap.php
@@ -2,6 +2,8 @@
require_once __DIR__."/../vendor/autoload.php";
require_once __DIR__."/systemtest.php";
+if (file_exists(__DIR__."/banner.php"))
+ require_once __DIR__."/banner.php";
use NoccyLabs\Hotfix\HotfixApplication;
diff --git a/bin/hotfix b/bin/hotfix
old mode 100644
new mode 100755
diff --git a/makephar b/makephar
new file mode 100755
index 0000000..ebb2ac9
Binary files /dev/null and b/makephar differ
diff --git a/src/Command/ApplyCommand.php b/src/Command/ApplyCommand.php
index d519a65..cc0cfef 100644
--- a/src/Command/ApplyCommand.php
+++ b/src/Command/ApplyCommand.php
@@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
+use Symfony\Component\Console\Question\ChoiceQuestion;
use NoccyLabs\Hotfix\Hotfix\Loader;
class ApplyCommand extends Command
@@ -20,6 +21,7 @@ class ApplyCommand extends Command
$this->setDescription("Apply a hotfix from a file or the Internet");
$this->addOption("insecure", "I", InputOption::VALUE_NONE, "Disable signature checks. Don't use unless you know what you are doing!");
+ $this->addOption("preview", "p", InputOption::VALUE_NONE, "Only preview the hotfix script, don't apply anything");
$this->addArgument("hotfix", InputArgument::OPTIONAL, "The identifier, path or filename of the hotfix");
}
@@ -30,10 +32,20 @@ class ApplyCommand extends Command
$fix = $input->getArgument("hotfix");
$insecure = $input->getOption("insecure");
+ $loader = new Loader();
+
+ if (!$fix) {
+
+ $loaders = $loader->getLoaders();
+ $output->writeln("Supported loaders:\n");
+ foreach ($loaders as $loader) {
+ $output->writeln(" * ".$loader->getInfo());
+ }
+ return;
+ }
$output->writeln("Reading hotfix {$fix}...");
- $loader = new Loader();
try {
$hotfix = $loader->load($fix, $insecure);
} catch (\Exception $e) {
@@ -47,20 +59,27 @@ class ApplyCommand extends Command
$output->writeln("");
if (($signer = $hotfix->getSignedBy())) {
- $output->writeln("Hotfix has good signature by {$signer}");
+ $keyid = $hotfix->getKeyId();
+ $output->writeln("Hotfix has good signature from {$signer} (keyid {$keyid})");
} else {
$output->writeln("Warning: Hotfix is not signed or signature not valid!");
}
$output->writeln("");
- $output->writeln(" Hotfix: ".$hotfix->getName()."");
+ $output->writeln(" Hotfix: ".$hotfix->getName()."");
$output->writeln(" Author: ".$hotfix->getAuthor()."");
- $output->writeln(" Info:");
- $info = explode("\n",wordwrap(trim($hotfix->getInfo()), 70));
- foreach ($info as $line) {
- $output->writeln(" | {$line}");
- }
+ $info = explode("\n",wordwrap(trim($hotfix->getInfo()), 60));
+ $info = "".join("\n ", $info)."";
+ $output->writeln(" Info: ".$info);
$output->writeln("");
+ if ($input->getOption("preview")) {
+ $output->writeln("This is the script that will be executed:");
+ $body = $hotfix->getBody();
+ $body = " ".join("\n ", explode("\n",$body))."";
+ $output->writeln($body);
+ return;
+ }
+
$helper = $this->getHelper("question");
$question = new ConfirmationQuestion("Do you want to apply this hotfix? [y/N] ", false);
diff --git a/src/Hotfix/Hotfix.php b/src/Hotfix/Hotfix.php
index 1fd5ed6..c827142 100644
--- a/src/Hotfix/Hotfix.php
+++ b/src/Hotfix/Hotfix.php
@@ -9,6 +9,8 @@ class Hotfix
protected $signer;
+ protected $keyId;
+
protected $header;
protected $body;
@@ -16,7 +18,8 @@ class Hotfix
public function __construct($hotfix, $signer)
{
$this->load($hotfix);
- $this->signer = $signer;
+ $this->signer = $signer[0];
+ $this->keyId = $signer[1];
}
protected function load($hotfix)
@@ -31,6 +34,11 @@ class Hotfix
$this->body = $body;
}
+ public function getBody()
+ {
+ return $this->body;
+ }
+
public function apply()
{
if (!array_key_exists('lang', $this->header)) {
@@ -40,9 +48,12 @@ class Hotfix
}
$script = null;
+ $head = null;
+ $foot = null;
switch ($lang) {
case 'bash':
$exec = "/bin/bash";
+ $head = file_get_contents(__DIR__."/../stubs/bash.stub");
break;
case 'php':
$exec = "/usr/bin/env php";
@@ -53,7 +64,7 @@ class Hotfix
}
$tmpfile = sys_get_temp_dir()."/hotfix_".sha1($this->header['hotfix']);
- file_put_contents($tmpfile, $this->body);
+ file_put_contents($tmpfile, $head."\n".$this->body."\n".$foot);
passthru($exec." ".$tmpfile);
unlink($tmpfile);
}
@@ -68,6 +79,11 @@ class Hotfix
$this->signer['uids'][0]['email']
);
}
+
+ public function getKeyId()
+ {
+ return $this->keyId;
+ }
public function getName()
{
diff --git a/src/Hotfix/Loader.php b/src/Hotfix/Loader.php
index be1ea47..ace3013 100644
--- a/src/Hotfix/Loader.php
+++ b/src/Hotfix/Loader.php
@@ -22,6 +22,11 @@ class Loader
$this->loaders[] = $loader;
}
+ public function getLoaders()
+ {
+ return $this->loaders;
+ }
+
public function load($fix, $insecure=false)
{
foreach ($this->loaders as $loader) {
@@ -56,12 +61,22 @@ class Loader
throw new \Exception("Hotfix signature is not valid!");
}
- $keyInfo = gnupg_keyinfo($gpg, $sigInfo[0]['fingerprint']);
+ $fingerprint = $sigInfo[0]['fingerprint'];
+ $keyInfo = gnupg_keyinfo($gpg, $fingerprint);
+
+ $subKeys = $keyInfo[0]['subkeys'];
+ $keyId = null;
+ foreach ($subKeys as $subKey) {
+ if ($subKey['fingerprint'] == $fingerprint) {
+ $keyId = $subKey['keyid'];
+ break;
+ }
+ }
if (empty($keyInfo)) {
throw new \Exception("Unknown signer (key id {$sigInfo[0]['fingerprint']})");
}
- return $keyInfo[0];
+ return [ $keyInfo[0], $keyId ];
}
}
diff --git a/src/Hotfix/Loader/FileLoader.php b/src/Hotfix/Loader/FileLoader.php
index b70b3f7..4240525 100644
--- a/src/Hotfix/Loader/FileLoader.php
+++ b/src/Hotfix/Loader/FileLoader.php
@@ -15,4 +15,9 @@ class FileLoader implements LoaderInterface
}
return false;
}
+
+ public function getInfo()
+ {
+ return "filename - Read a hotfix from a file";
+ }
}
diff --git a/src/Hotfix/Loader/GistLoader.php b/src/Hotfix/Loader/GistLoader.php
index c9d13c9..85b099e 100644
--- a/src/Hotfix/Loader/GistLoader.php
+++ b/src/Hotfix/Loader/GistLoader.php
@@ -15,4 +15,9 @@ class GistLoader implements LoaderInterface
return file_get_contents($url);
}
+
+ public function getInfo()
+ {
+ return "gist:user/gist-id - Read hotfix from a Gist";
+ }
}
diff --git a/src/Hotfix/Loader/HttpLoader.php b/src/Hotfix/Loader/HttpLoader.php
index a78dee3..7383b74 100644
--- a/src/Hotfix/Loader/HttpLoader.php
+++ b/src/Hotfix/Loader/HttpLoader.php
@@ -12,4 +12,9 @@ class HttpLoader implements LoaderInterface
}
return false;
}
+
+ public function getInfo()
+ {
+ return "http(s)://url - Read hotfix from a URL";
+ }
}
diff --git a/src/Hotfix/Loader/PastebinLoader.php b/src/Hotfix/Loader/PastebinLoader.php
index a6ddf71..43c5d3e 100644
--- a/src/Hotfix/Loader/PastebinLoader.php
+++ b/src/Hotfix/Loader/PastebinLoader.php
@@ -20,4 +20,9 @@ class PastebinLoader implements LoaderInterface
return $body;
}
+
+ public function getInfo()
+ {
+ return "pastebin:paste-id - Read hotfix from Pastebin";
+ }
}
diff --git a/src/stubs/bash.stub b/src/stubs/bash.stub
new file mode 100644
index 0000000..a43f9a2
--- /dev/null
+++ b/src/stubs/bash.stub
@@ -0,0 +1,16 @@
+test -e /etc/lsb-release && source /etc/lsb-release
+
+function exec() {
+ echo -e "\e[36;1m[exec]\e[36;21m $*\e[0m"
+ LOG=$(tempfile -p exec)
+ $@ &>$LOG
+ EC=$?
+ if [ $EC -gt 0 ]; then
+ echo -e "\e[31;1m[warn]\e[31;21m Command completed with exitcode $EC\e[0m"
+ cat $LOG
+ fi
+ rm $LOG
+}
+function info() {
+ echo -e "\e[32;1m[info]\e[32;21m $*\e[0m"
+}