Skip to content

Commit 137dbfd

Browse files
authored
#41 Replace console_commandline (#42)
1 parent 6d307aa commit 137dbfd

9 files changed

Lines changed: 502 additions & 78 deletions

File tree

.github/workflows/tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
fail-fast: true
1414
matrix:
15-
php: ["5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4"]
15+
php: ["5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5"]
1616

1717
name: PHP ${{ matrix.php }}
1818

@@ -41,10 +41,10 @@ jobs:
4141
run: composer install --prefer-dist --no-interaction --no-progress
4242

4343
- name: Install GnuPG v1 (GnuPG v2 does not work with Github Actions)
44-
run: sudo apt-get install -y gnupg1
44+
run: sudo apt-get install -y gnupg2
4545

4646
- name: Execute tests
47-
run: TESTS_GPG_BINARY=/usr/bin/gpg1 vendor/bin/phpunit --stop-on-error tests
47+
run: TESTS_GPG_BINARY=/usr/bin/gpg vendor/bin/phpunit --stop-on-error tests
4848

4949
- name: Upload artifacts
5050
uses: actions/upload-artifact@master

Crypt/Console/PinCliParameters.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Crypt\Console;
4+
5+
class PinCliParameters
6+
{
7+
private $verbose;
8+
private $log;
9+
10+
public function __construct($verbose = 0, $log = null) {
11+
$this->verbose = $verbose;
12+
$this->log = $log;
13+
}
14+
15+
public function getVerbose() {
16+
return $this->verbose;
17+
}
18+
19+
public function getLog() {
20+
return $this->log;
21+
}
22+
}

Crypt/Console/SimpleCliWrapper.php

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
<?php
2+
3+
namespace Crypt\Console;
4+
5+
6+
require_once __DIR__ . '/PinCliParameters.php';
7+
8+
class SimpleCliWrapper
9+
{
10+
const DEFAULT_VERBOSITY = 0;
11+
const INVALID_INPUT = -1;
12+
const VERBOSE_LONG = 'verbose';
13+
const VERBOSE_SHORT = 'v';
14+
const HELP_SHORT = 'h';
15+
const HELP_LONG = 'help';
16+
const LOG_SHORT = 'l';
17+
const LOG_LONG = 'log';
18+
const OPTIONAL_INDICATOR = '::';
19+
20+
/**
21+
* The old definition for the CLI options was:
22+
* ```xml
23+
* <description>Utility that emulates GnuPG 1.x passphrase handling over pipe-based IPC for GnuPG 2.x.</description>
24+
* <version>@package-version@</version>
25+
* <option name="log">
26+
* <short_name>-l</short_name>
27+
* <long_name>--log</long_name>
28+
* <description>Optional location to log pinentry activity.</description>
29+
* <action>StoreString</action>
30+
* </option>
31+
* <option name="verbose">
32+
* <short_name>-v</short_name>
33+
* <long_name>--verbose</long_name>
34+
* <description>Sets verbosity level. Use multiples for more detail (e.g. "-vv").</description>
35+
* <action>Counter</action>
36+
* <default>0</default>
37+
* </option>
38+
* </description>
39+
* ```
40+
*
41+
* @return PinCliParameters
42+
*/
43+
public function parseCli()
44+
{
45+
$shortOpts = implode('', [
46+
self::VERBOSE_SHORT . self::OPTIONAL_INDICATOR,
47+
self::LOG_SHORT . self::OPTIONAL_INDICATOR,
48+
self::HELP_SHORT . self::OPTIONAL_INDICATOR
49+
]);
50+
51+
$longOpts = [
52+
self::VERBOSE_LONG . self::OPTIONAL_INDICATOR,
53+
self::LOG_LONG . self::OPTIONAL_INDICATOR,
54+
self::HELP_LONG . self::OPTIONAL_INDICATOR
55+
];
56+
57+
$opts = getopt($shortOpts, $longOpts);
58+
if (isset($opts[self::HELP_SHORT]) || isset($opts[self::HELP_LONG])) {
59+
$this->printHelp();
60+
exit(1);
61+
}
62+
63+
$verbosityLevel = self::getVerbosityLevel($opts);
64+
if ($verbosityLevel === self::INVALID_INPUT) {
65+
$this->writeToErrOrEcho("Invalid verbosity level. Please use -h or --help.\n");
66+
exit(1);
67+
}
68+
69+
$logLocation = self::getLogLocation($opts);
70+
if ($logLocation === self::INVALID_INPUT) {
71+
$this->writeToErrOrEcho("Invalid log location. Please use -h or --help.\n");
72+
exit(1);
73+
}
74+
75+
return new PinCliParameters(
76+
$verbosityLevel,
77+
$logLocation
78+
);
79+
}
80+
81+
/**
82+
* replication of previous behavior from PEAR Console_CommandLine
83+
* which is abandoned now.
84+
*
85+
* ```
86+
* public function stderr($msg)
87+
* {
88+
* if (defined('STDERR')) {
89+
* fwrite(STDERR, $msg);
90+
* } else {
91+
* echo $msg;
92+
* }
93+
* }
94+
* ```
95+
*
96+
* @param $msg
97+
* @return void
98+
*/
99+
public function writeToErrOrEcho($msg)
100+
{
101+
if (defined('STDERR')) {
102+
fwrite(STDERR, $msg);
103+
} else {
104+
echo $msg;
105+
}
106+
}
107+
108+
private function printHelp()
109+
{
110+
echo "
111+
Utility that emulates GnuPG 1.x passphrase handling over pipe-based IPC for GnuPG 2.x.
112+
113+
Options:
114+
-h, --help: Display this help message.
115+
-l, --log: Optional location to log pinentry activity.
116+
-v, --verbose: Verbosity level for logging.
117+
118+
The default verbosity level is 0.
119+
Increase verbosity levels for more detail:
120+
Short Syntax: -vvv
121+
Long Syntax: --verbose 3
122+
123+
Set the Log Location:
124+
Short Syntax: -l/path/to/log/file
125+
Long Syntax: --log /path/to/log/file
126+
127+
the short syntax will be taken before the long syntax.
128+
";
129+
}
130+
131+
132+
/**
133+
* @param array $opts
134+
*
135+
* @return int
136+
*/
137+
public static function getVerbosityLevel(array $opts)
138+
{
139+
if (!isset($opts[self::VERBOSE_SHORT]) && !isset($opts[self::VERBOSE_LONG])) {
140+
return self::DEFAULT_VERBOSITY;
141+
}
142+
143+
144+
// the default options with just a -v is false, but based
145+
// on the old system, it would be level 0
146+
if (isset($opts[self::VERBOSE_SHORT])) {
147+
if ($opts[self::VERBOSE_SHORT] === false) {
148+
return self::DEFAULT_VERBOSITY;
149+
}
150+
151+
// the first v will be stripped -v so we count the amounts of v's after that
152+
return (int)mb_strlen($opts[self::VERBOSE_SHORT]);
153+
}
154+
155+
if (isset($opts[self::VERBOSE_LONG]) && !is_numeric($opts[self::VERBOSE_LONG])) {
156+
return self::INVALID_INPUT;
157+
}
158+
159+
if (isset($opts[self::VERBOSE_LONG])) {
160+
return (int)$opts[self::VERBOSE_LONG];
161+
}
162+
163+
return self::INVALID_INPUT;
164+
165+
}
166+
167+
168+
public static function getLogLocation(array $opts)
169+
{
170+
if (!isset($opts[self::LOG_SHORT]) && !isset($opts[self::LOG_LONG])) {
171+
return "";
172+
}
173+
174+
if (isset($opts[self::LOG_SHORT]) && is_string($opts[self::LOG_SHORT])) {
175+
return $opts[self::LOG_SHORT];
176+
}
177+
178+
if (isset($opts[self::LOG_LONG]) && is_string($opts[self::LOG_LONG])) {
179+
return $opts[self::LOG_LONG];
180+
}
181+
182+
return self::INVALID_INPUT;
183+
}
184+
}

Crypt/GPG/PinEntry.php

Lines changed: 10 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
/**
3333
* CLI user-interface and parser.
3434
*/
35-
require_once 'Console/CommandLine.php';
35+
require_once __DIR__ . '/../Console/SimpleCliWrapper.php';
3636

3737
/**
3838
* A command-line dummy pinentry program for use with gpg-agent and Crypt_GPG
@@ -137,7 +137,7 @@ class Crypt_GPG_PinEntry
137137
/**
138138
* The command-line interface parser for this pinentry
139139
*
140-
* @var Console_CommandLine
140+
* @var \Crypt\Console\SimpleCliWrapper
141141
*
142142
* @see Crypt_GPG_PinEntry::getParser()
143143
*/
@@ -192,13 +192,13 @@ class Crypt_GPG_PinEntry
192192
*/
193193
public function __invoke()
194194
{
195-
$this->parser = $this->getCommandLineParser();
195+
$this->parser = new \Crypt\Console\SimpleCliWrapper();
196196

197197
try {
198-
$result = $this->parser->parse();
198+
$result = $this->parser->parseCli();
199199

200-
$this->setVerbosity($result->options['verbose']);
201-
$this->setLogFilename($result->options['log']);
200+
$this->setVerbosity($result->getVerbose());
201+
$this->setLogFilename($result->getLog());
202202

203203
$this->connect();
204204
$this->initPinsFromENV();
@@ -211,10 +211,6 @@ public function __invoke()
211211
}
212212

213213
$this->disconnect();
214-
215-
} catch (Console_CommandLine_Exception $e) {
216-
$this->log($e->getMessage() . PHP_EOL, self::VERBOSITY_ERRORS);
217-
exit(1);
218214
} catch (Exception $e) {
219215
$this->log($e->getMessage() . PHP_EOL, self::VERBOSITY_ERRORS);
220216
$this->log($e->getTraceAsString() . PHP_EOL, self::VERBOSITY_ERRORS);
@@ -259,57 +255,19 @@ public function setLogFilename($filename)
259255
}
260256

261257
if ($filename != '') {
262-
if (($this->logFile = fopen($filename, 'w')) === false) {
258+
if (($this->logFile = fopen($filename, 'wb')) === false) {
263259
$this->log(
264260
'Unable to open log file "' . $filename . '" '
265261
. 'for writing.' . PHP_EOL,
266262
self::VERBOSITY_ERRORS
267263
);
268264
exit(1);
269-
} else {
270-
stream_set_write_buffer($this->logFile, 0);
271265
}
272-
}
273266

274-
return $this;
275-
}
276-
277-
/**
278-
* Gets the CLI user-interface definition for this pinentry
279-
*
280-
* Detects whether or not this package is PEAR-installed and appropriately
281-
* locates the XML UI definition.
282-
*
283-
* @return string|null The location of the CLI user-interface definition XML.
284-
*/
285-
protected function getUIXML()
286-
{
287-
// Find PinEntry config depending on the way how the package is installed
288-
$ds = DIRECTORY_SEPARATOR;
289-
$root = __DIR__ . $ds . '..' . $ds . '..' . $ds;
290-
$paths = [
291-
'@data-dir@' . $ds . '@package-name@' . $ds . 'data', // PEAR
292-
$root . 'data', // Git
293-
$root . 'data' . $ds . 'Crypt_GPG' . $ds . 'data', // Composer
294-
];
295-
296-
foreach ($paths as $path) {
297-
if (file_exists($path . $ds . 'pinentry-cli.xml')) {
298-
return $path . $ds . 'pinentry-cli.xml';
299-
}
267+
stream_set_write_buffer($this->logFile, 0);
300268
}
301269

302-
return null;
303-
}
304-
305-
/**
306-
* Gets the CLI parser for this pinentry
307-
*
308-
* @return Console_CommandLine the CLI parser for this pinentry.
309-
*/
310-
protected function getCommandLineParser()
311-
{
312-
return Console_CommandLine::fromXmlFile($this->getUIXML());
270+
return $this;
313271
}
314272

315273
/**
@@ -331,7 +289,7 @@ protected function log($data, $level)
331289
fwrite($this->logFile, $data);
332290
fflush($this->logFile);
333291
} else {
334-
$this->parser->outputter->stderr($data);
292+
$this->parser->writeToErrOrEcho($data);
335293
}
336294
}
337295

composer.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525
}
2626
],
2727
"require": {
28-
"php": ">=5.4.8",
28+
"php": ">=5.6",
2929
"ext-mbstring": "*",
30-
"pear/console_commandline": "*",
3130
"pear/pear_exception": "*"
3231
},
3332
"suggest": {
@@ -52,5 +51,10 @@
5251
},
5352
"archive": {
5453
"exclude": ["tools"]
54+
},
55+
"config": {
56+
"audit": {
57+
"block-insecure": false
58+
}
5559
}
5660
}

data/pinentry-cli.xml

Lines changed: 0 additions & 18 deletions
This file was deleted.

scripts/crypt-gpg-pinentry

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ $root = __DIR__ . $ds . '..' ;
1010
$paths = [
1111
'@php-dir@', // PEAR or Composer
1212
$root, // Git (or Composer with wrong @php-dir@)
13-
$root . $ds . '..' . $ds . 'Console_CommandLine', // Composer
14-
$root . $ds . '..' . $ds . 'console_commandline', // Composer
1513
// and composer-installed PEAR_Exception for Console_CommandLine (#21074)
1614
$root . $ds . '..' . $ds . '..' . $ds . 'pear' . $ds . 'pear_exception',
1715
];

0 commit comments

Comments
 (0)