*.tmp
*.phar
*.phar.gz
-*.phar.bz2
\ No newline at end of file
+*.phar.bz2
+build/pharext.key
+*.phar*
+*.pubkey
--- /dev/null
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5x9bwisjDBDV/bwDiju2
+Ebx4kPir32WwT3+hxV0/qAPclA1WsrpcUJ7BChk+Rlz8ujOcyENTidgI1vj3oUpo
+/P9XlLQOSrJHYz+AOg7qwhTe89xIJspS4gHHiXUAmxz0TyCNMbOyrLcjP5CmZdll
+n+e3HP8Kfipr4XyWBhsKbdYUZ8Ga6IeFMYzNqCzWazcOasdCpsablmyrfCaZoJ0l
+bFald0nF3/YoeYgo3fWb4Md9Xf/grpz8Ocqyq4OY49Vb0/p8FMwzBV6vbVh/eAV/
+jrP7L40Jw97nSBrP/5nK8Ylc5BayVRq/HhT3kLMC//zvPjb8xz3ZgVTQrwWTF3Zy
++wIDAQAB
+-----END PUBLIC KEY-----
* Creates bin/pharext, invoked through the Makefile
*/
-$pkguniq = uniqid();
$pkgname = __DIR__."/../bin/pharext";
-$tmpname = "$pkgname.$pkguniq.phar.tmp";
+$tmpname = __DIR__."/pharext.phar";
if (file_exists($tmpname)) {
if (!unlink($tmpname)) {
}
$package = new \Phar($tmpname, 0, "pharext.phar");
+
+if (getenv("SIGN")) {
+ shell_exec("stty -echo");
+ printf("Password: ");
+ $password = fgets(STDIN, 1024);
+ printf("\n");
+ shell_exec("stty echo");
+ if (substr($password, -1) == "\n") {
+ $password = substr($password, 0, -1);
+ }
+
+ $pkey = openssl_pkey_get_private("file://".__DIR__."/pharext.key", $password);
+ if (!is_resource($pkey)) {
+ $this->error("Could not load private key %s/pharext.key", __DIR__);
+ exit(3);
+ }
+ if (!openssl_pkey_export($pkey, $key)) {
+ $this->error(null);
+ exit(3);
+ }
+
+ $package->setSignatureAlgorithm(Phar::OPENSSL, $key);
+}
+
$package->buildFromDirectory(dirname(__DIR__)."/src", "/^.*\.php$/");
$package->setDefaultStub("pharext_packager.php");
$package->setStub("#!/usr/bin/php -dphar.readonly=0\n".$package->getStub());
"keywords": ["ext", "extension", "phar", "package", "install"],
"type": "project",
"license": "BSD-2-Clause",
- "bin": ["bin/pharext"]
+ "bin": ["bin/pharext", "bin/pharext.pubkey"]
}
}
return sprintf("%s/%s.%s", sys_get_temp_dir(), $prefix, $suffix);
}
-}
\ No newline at end of file
+
+ /**
+ * Create a new temp directory
+ * @param string $prefix
+ * @return string
+ */
+ private function newtemp($prefix) {
+ $temp = $this->tempname($prefix);
+ if (!is_dir($temp)) {
+ if (!mkdir($temp, 0700, true)) {
+ $this->error(null);
+ exit(3);
+ }
+ }
+ return $temp;
+ }
+
+ /**
+ * rm -r
+ * @param string $dir
+ */
+ private function rm($dir) {
+ foreach (scandir($dir) as $entry) {
+ if ($entry === "." || $entry === "..") {
+ continue;
+ } elseif (is_dir("$dir/$entry")) {
+ $this->rm("$dir/$entry");
+ } elseif (!unlink("$dir/$entry")) {
+ $this->error(null);
+ }
+ }
+ if (!rmdir($dir)) {
+ $this->error(null);
+ }
+ }
+}
}
}
- /**
- * Create a new temp directory
- * @param string $prefix
- * @return string
- */
- private function newtemp($prefix) {
- $temp = $this->tempname($prefix);
- if (!is_dir($temp)) {
- if (!mkdir($temp, 0750, true)) {
- $this->error(null);
- exit(3);
- }
- }
- return $temp;
- }
-
/**
* Prepares, configures, builds and installs the extension
*/
}
}
- /**
- * rm -r
- * @param string $dir
- */
- private function rm($dir) {
- foreach (scandir($dir) as $entry) {
- if ($entry === "." || $entry === "..") {
- continue;
- } elseif (is_dir("$dir/$entry")) {
- $this->rm("$dir/$entry");
- } elseif (!unlink("$dir/$entry")) {
- $this->error(null);
- }
- }
- if (!rmdir($dir)) {
- $this->error(null);
- }
- }
-
/**
* Execute a program with escalated privileges handling interactive password prompt
* @param string $command
--- /dev/null
+<?php
+
+namespace pharext\Openssl;
+
+class PrivateKey
+{
+ private $key;
+
+ function __construct($file, $password) {
+ $this->key = openssl_pkey_get_private("file://$file", $password);
+ if (!is_resource($this->key)) {
+ throw new \Exception("Could not load private key");
+ }
+ }
+
+ function sign(\Phar $package) {
+ $package->setSignatureAlgorithm(\Phar::OPENSSL, $this->key);
+ }
+
+ function exportPublicKey($file) {
+ if (!file_put_contents("$file.tmp", openssl_pkey_get_details($this->key)["key"])
+ || !rename("$file.tmp", $file)
+ ) {
+ throw new \Exception(error_get_last()["message"]);
+ }
+ }
+}
$this->args = new CliArgs([
["h", "help", "Display this help",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
+ [null, "signature", "Dump signature",
+ CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG|CliArgs::HALT],
["v", "verbose", "More output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["q", "quiet", "Less output",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
["Z", "bzip", "Create additional PHAR compressed with bzip",
CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::NOARG],
+ ["S", "sign", "Sign the *.ext.phar with a private key",
+ CliArgs::OPTIONAL|CliArgs::SINGLE|CliArgs::REQARG]
]);
}
$this->help($prog);
exit;
}
+ if ($this->args["signature"]) {
+ exit($this->signature($prog));
+ }
try {
if ($this->args["source"]) {
$this->createPackage();
}
-
+
+ function signature($prog) {
+ try {
+ $sig = (new Phar(Phar::running(false)))->getSignature();
+ printf("%s signature of %s\n%s", $sig["hash_type"], $prog,
+ chunk_split($sig["hash"], 64, "\n"));
+ return 0;
+ } catch (\Exception $e) {
+ $this->error("%s\n", $e->getMessage());
+ return 2;
+ }
+ }
+
/**
* Traverses all pharext source files to bundle
* @return Generator
}
}
+ private function askpass($prompt = "Password:") {
+ system("stty -echo", $retval);
+ if ($retval) {
+ $this->error("Could not disable echo on the terminal\n");
+ }
+ printf("%s ", $prompt);
+ $pass = fgets(STDIN, 1024);
+ system("stty echo");
+ if (substr($pass, -1) == "\n") {
+ $pass = substr($pass, 0, -1);
+ }
+ return $pass;
+ }
+
/**
* Creates the extension phar
*/
$this->info("Creating phar %s ...%s", $pkgtemp, $this->args->verbose ? "\n" : " ");
try {
$package = new Phar($pkgtemp);
+
+ if ($this->args->sign) {
+ $this->info("\nUsing private key to sign phar ... \n");
+ $privkey = new Openssl\PrivateKey(realpath($this->args->sign), $this->askpass());
+ $privkey->sign($package);
+ }
+
$package->startBuffering();
$package->buildFromIterator($this->source, $this->source->getBaseDir());
$package->buildFromIterator($this->bundle());
$package->setDefaultStub("pharext_installer.php");
$package->setStub("#!/usr/bin/php -dphar.readonly=1\n".$package->getStub());
$package->stopBuffering();
-
+
if (!chmod($pkgtemp, 0777)) {
$this->error(null);
} elseif ($this->args->verbose) {
$this->error("%s\n", $e->getMessage());
}
}
-
+
unset($package);
} catch (\Exception $e) {
$this->error("%s\n", $e->getMessage());
exit(5);
}
$this->info("OK\n");
+ if ($this->args->sign && isset($privkey)) {
+ $keyname = $this->args->dest ."/". basename($pkgfile) . ".pubkey";
+ $this->info("Public Key %s ... ", $keyname);
+ try {
+ $privkey->exportPublicKey($keyname);
+ $this->info("OK\n");
+ } catch (\Exception $e) {
+ $this->error("%s", $e->getMessage());
+ }
+ }
}
}
}
return $fi->getRealpath();
}, $filtered);
sort($fltfiles);
-
+ $this->assertEquals(array(), array_diff($gitfiles, $fltfiles));
$this->assertEquals($gitfiles, $fltfiles);
}
}
\ No newline at end of file