Skip to content

Commit

Permalink
Merge pull request #5 from malukenho/basic-signer-and-checker
Browse files Browse the repository at this point in the history
Basic signer and checker
  • Loading branch information
asgrim committed Dec 23, 2016
2 parents 6f3556f + fc5c091 commit b476e4c
Show file tree
Hide file tree
Showing 12 changed files with 286 additions and 5 deletions.
9 changes: 4 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@
"php": "^7.0|^7.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^1.12",
"phpunit/phpunit": "^5.4"
"phpunit/phpunit": "^5.6"
},
"autoload": {
"psr-4": {
"Signature\\": "src"
"Roave\\Signature\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"SignatureTest\\": "test/unit",
"SignatureTestFixture\\": "test/fixture"
"Roave\\SignatureTest\\": "test/unit",
"Roave\\SignatureTestFixture\\": "test/fixture"
}
},
"minimum-stability": "dev",
Expand Down
15 changes: 15 additions & 0 deletions src/CheckerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Roave\Signature;

interface CheckerInterface
{
/**
* @param string $phpCode
*
* @return bool
*/
public function check(string $phpCode): bool;
}
24 changes: 24 additions & 0 deletions src/Encoder/Base64Encoder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types=1);

namespace Roave\Signature\Encoder;

final class Base64Encoder implements EncoderInterface
{
/**
* {@inheritDoc}
*/
public function encode(string $codeWithoutSignature): string
{
return base64_encode($codeWithoutSignature);
}

/**
* {@inheritDoc}
*/
public function verify(string $codeWithoutSignature, string $signature): bool
{
return hash_equals($this->encode($codeWithoutSignature), $signature);
}
}
12 changes: 12 additions & 0 deletions src/Encoder/EncoderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Roave\Signature\Encoder;

interface EncoderInterface
{
public function encode(string $codeWithoutSignature): string;

public function verify(string $codeWithoutSignature, string $signature): bool;
}
45 changes: 45 additions & 0 deletions src/FileContentChecker.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

namespace Roave\Signature;

use Roave\Signature\Encoder\EncoderInterface;

final class FileContentChecker implements CheckerInterface
{
/**
* @var EncoderInterface
*/
private $encoder;

/**
* {@inheritDoc}
*/
public function __construct(EncoderInterface $encoder)
{
$this->encoder = $encoder;
}

/**
* {@inheritDoc}
*/
public function check(string $phpCode): bool
{
if (! preg_match('{Roave/Signature:\s+([a-zA-Z0-9\/=]+)}', $phpCode, $matches)) {
return false;
}

return $this->encoder->verify($this->stripCodeSignature($phpCode), $matches[1]);
}

/**
* @param string $phpCode
*
* @return string
*/
private function stripCodeSignature(string $phpCode): string
{
return preg_replace('{[\/\*\s]+Roave/Signature:\s+([a-zA-Z0-9\/\*\/ =]+)}', '', $phpCode);
}
}
28 changes: 28 additions & 0 deletions src/FileContentSigner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Roave\Signature;

use Roave\Signature\Encoder\EncoderInterface;

final class FileContentSigner implements SignerInterface
{
/**
* @var EncoderInterface
*/
private $encoder;

/**
* {@inheritDoc}
*/
public function __construct(EncoderInterface $encoder)
{
$this->encoder = $encoder;
}

public function sign(string $phpCode): string
{
return 'Roave/Signature: ' . $this->encoder->encode($phpCode);
}
}
10 changes: 10 additions & 0 deletions src/SignerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Roave\Signature;

interface SignerInterface
{
public function sign(string $phpCode) : string;
}
12 changes: 12 additions & 0 deletions test/fixture/UserClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Roave\SignatureTestFixture;

class UserClass
{
public $name;

protected $surname;

private $age;
}
13 changes: 13 additions & 0 deletions test/fixture/UserClassSignedByFileContent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
/** Roave/Signature: YToxOntpOjA7czoxNDE6Ijw/cGhwCgpuYW1lc3BhY2UgU2lnbmF0dXJlVGVzdEZpeHR1cmU7CgpjbGFzcyBVc2VyQ2xhc3NTaWduZWRCeUZpbGVDb250ZW50CnsKICAgIHB1YmxpYyAkbmFtZTsKCiAgICBwcm90ZWN0ZWQgJHN1cm5hbWU7CgogICAgcHJpdmF0ZSAkYWdlOwp9CiI7fQ== */

namespace Roave\SignatureTestFixture;

class UserClassSignedByFileContent
{
public $name;

protected $surname;

private $age;
}
21 changes: 21 additions & 0 deletions test/unit/src/Encoder/Base64EncoderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Roave\SignatureTest\Encoder;

use Roave\Signature\Encoder\Base64Encoder;

/**
* @covers \Roave\Signature\Encoder\Base64Encoder
*/
final class Base64EncoderTest extends \PHPUnit_Framework_TestCase
{
public function testEncode()
{
$encoder = new Base64Encoder();

self::assertSame('IA==', $encoder->encode(' '));
self::assertSame('PD9waHA=', $encoder->encode('<?php'));
}
}
77 changes: 77 additions & 0 deletions test/unit/src/FileContentCheckerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

namespace Roave\SignatureTest;

use PHPUnit_Framework_TestCase;
use Roave\Signature\Encoder\Base64Encoder;
use Roave\Signature\Encoder\EncoderInterface;
use Roave\Signature\FileContentChecker;

/**
* @covers \Roave\Signature\FileContentChecker
*/
final class FileContentCheckerTest extends PHPUnit_Framework_TestCase
{
/**
* @var EncoderInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $encoder;

/**
* {@inheritDoc}
*/
protected function setUp()
{
parent::setUp();

$this->encoder = $this->createMock(EncoderInterface::class);
}

public function testShouldCheckClassFileContent()
{
$classFilePath = __DIR__ . '/../../fixture/UserClassSignedByFileContent.php';

self::assertFileExists($classFilePath);

$checker = new FileContentChecker(new Base64Encoder());

$checker->check(file_get_contents($classFilePath));
}

public function testShouldReturnFalseIfSignatureDoesNotMatch()
{
$classFilePath = __DIR__ . '/../../fixture/UserClassSignedByFileContent.php';

self::assertFileExists($classFilePath);

$expectedSignature = 'YToxOntpOjA7czoxNDE6Ijw/cGhwCgpuYW1lc3BhY2UgU2lnbmF0dXJlVGVzdEZpeHR1cmU7' .
'CgpjbGFzcyBVc2VyQ2xhc3NTaWduZWRCeUZpbGVDb250ZW50CnsKICAgIHB1YmxpYyAkbmFtZTsKCiAgICBwcm90ZW' .
'N0ZWQgJHN1cm5hbWU7CgogICAgcHJpdmF0ZSAkYWdlOwp9CiI7fQ==';

$this->encoder->expects(self::once())->method('verify')->with(
str_replace(
'/** Roave/Signature: ' . $expectedSignature . ' */' . "\n",
'',
file_get_contents($classFilePath)
),
$expectedSignature
);

$checker = new FileContentChecker($this->encoder);

self::assertFalse($checker->check(file_get_contents($classFilePath)));
}

public function testShouldReturnFalseIfClassIsNotSigned()
{
$classFilePath = __DIR__ . '/../../fixture/UserClass.php';

self::assertFileExists($classFilePath);

$checker = new FileContentChecker($this->encoder);

self::assertFalse($checker->check(file_get_contents($classFilePath)));
}
}
25 changes: 25 additions & 0 deletions test/unit/src/FileContentSignerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Roave\SignatureTest;

use PHPUnit_Framework_TestCase;
use Roave\Signature\Encoder\Base64Encoder;
use Roave\Signature\FileContentSigner;

/**
* @covers \Roave\Signature\FileContentSigner
*/
final class FileContentSignerTest extends PHPUnit_Framework_TestCase
{
public function testSign()
{
$signer = new FileContentSigner(new Base64Encoder());

self::assertSame('Roave/Signature: PD9waHA=', $signer->sign('<?php'));
self::assertSame('Roave/Signature: PD9waHAK', $signer->sign('<?php' . "\n"));
self::assertSame('Roave/Signature: PGh0bWw+', $signer->sign('<html>'));
self::assertSame('Roave/Signature: cGxhaW4gdGV4dA==', $signer->sign('plain text'));
}
}

0 comments on commit b476e4c

Please sign in to comment.