Skip to content

Commit

Permalink
Update vendor libs
Browse files Browse the repository at this point in the history
  • Loading branch information
aheinze committed Sep 19, 2024
1 parent 4572b25 commit 43dc722
Show file tree
Hide file tree
Showing 4 changed files with 381 additions and 0 deletions.
56 changes: 56 additions & 0 deletions lib/vendor/bacon/bacon-qr-code/src/Renderer/Eye/PointyEye.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
declare(strict_types = 1);

namespace BaconQrCode\Renderer\Eye;

use BaconQrCode\Renderer\Path\Path;

/**
* Renders the outer eye as solid with a curved corner and inner eye as a circle.
*/
final class PointyEye implements EyeInterface
{
/**
* @var self|null
*/
private static $instance;

private function __construct()
{
}

public static function instance() : self
{
return self::$instance ?: self::$instance = new self();
}

public function getExternalPath() : Path
{
return (new Path())
->move(-3.5, 3.5)
->line(-3.5, 0)
->ellipticArc(3.5, 3.5, 0, false, true, 0, -3.5)
->line(3.5, -3.5)
->line(3.5, 3.5)
->close()
->move(2.5, 0)
->ellipticArc(2.5, 2.5, 0, false, true, 0, 2.5)
->ellipticArc(2.5, 2.5, 0, false, true, -2.5, 0)
->ellipticArc(2.5, 2.5, 0, false, true, 0, -2.5)
->ellipticArc(2.5, 2.5, 0, false, true, 2.5, 0)
->close()
;
}

public function getInternalPath() : Path
{
return (new Path())
->move(1.5, 0)
->ellipticArc(1.5, 1.5, 0., false, true, 0., 1.5)
->ellipticArc(1.5, 1.5, 0., false, true, -1.5, 0.)
->ellipticArc(1.5, 1.5, 0., false, true, 0., -1.5)
->ellipticArc(1.5, 1.5, 0., false, true, 1.5, 0.)
->close()
;
}
}
238 changes: 238 additions & 0 deletions lib/vendor/bacon/bacon-qr-code/src/Renderer/GDLibRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
<?php

declare(strict_types=1);

namespace BaconQrCode\Renderer;

use BaconQrCode\Encoder\ByteMatrix;
use BaconQrCode\Encoder\MatrixUtil;
use BaconQrCode\Encoder\QrCode;
use BaconQrCode\Exception\InvalidArgumentException;
use BaconQrCode\Exception\RuntimeException;
use BaconQrCode\Renderer\Color\Alpha;
use BaconQrCode\Renderer\Color\ColorInterface;
use BaconQrCode\Renderer\RendererStyle\EyeFill;
use BaconQrCode\Renderer\RendererStyle\Fill;
use GdImage;

final class GDLibRenderer implements RendererInterface
{
private ?GdImage $image;

/**
* @var array<string, int>
*/
private array $colors;

public function __construct(
private int $size,
private int $margin = 4,
private string $imageFormat = 'png',
private int $compressionQuality = 9,
private ?Fill $fill = null
) {
if (! extension_loaded('gd') || ! function_exists('gd_info')) {
throw new RuntimeException('You need to install the GD extension to use this back end');
}

if ($this->fill === null) {
$this->fill = Fill::default();
}
if ($this->fill->hasGradientFill()) {
throw new InvalidArgumentException('GDLibRenderer does not support gradients');
}
}

/**
* @throws InvalidArgumentException if matrix width doesn't match height
*/
public function render(QrCode $qrCode): string
{
$matrix = $qrCode->getMatrix();
$matrixSize = $matrix->getWidth();

if ($matrixSize !== $matrix->getHeight()) {
throw new InvalidArgumentException('Matrix must have the same width and height');
}

MatrixUtil::removePositionDetectionPatterns($matrix);
$this->newImage();
$this->draw($matrix);

return $this->renderImage();
}

private function newImage(): void
{
$img = imagecreatetruecolor($this->size, $this->size);
if ($img === false) {
throw new RuntimeException('Failed to create image of that size');
}

$this->image = $img;
imagealphablending($this->image, false);
imagesavealpha($this->image, true);


$bg = $this->getColor($this->fill->getBackgroundColor());
imagefilledrectangle($this->image, 0, 0, $this->size, $this->size, $bg);
imagealphablending($this->image, true);
}

private function draw(ByteMatrix $matrix): void
{
$matrixSize = $matrix->getWidth();

$pointsOnSide = $matrix->getWidth() + $this->margin * 2;
$pointInPx = $this->size / $pointsOnSide;

$this->drawEye(0, 0, $pointInPx, $this->fill->getTopLeftEyeFill());
$this->drawEye($matrixSize - 7, 0, $pointInPx, $this->fill->getTopRightEyeFill());
$this->drawEye(0, $matrixSize - 7, $pointInPx, $this->fill->getBottomLeftEyeFill());

$rows = $matrix->getArray()->toArray();
$color = $this->getColor($this->fill->getForegroundColor());
for ($y = 0; $y < $matrixSize; $y += 1) {
for ($x = 0; $x < $matrixSize; $x += 1) {
if (! $rows[$y][$x]) {
continue;
}

$points = $this->normalizePoints([
($this->margin + $x) * $pointInPx, ($this->margin + $y) * $pointInPx,
($this->margin + $x + 1) * $pointInPx, ($this->margin + $y) * $pointInPx,
($this->margin + $x + 1) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
($this->margin + $x) * $pointInPx, ($this->margin + $y + 1) * $pointInPx,
]);
imagefilledpolygon($this->image, $points, $color);
}
}
}

private function drawEye(int $xOffset, int $yOffset, float $pointInPx, EyeFill $eyeFill): void
{
$internalColor = $this->getColor($eyeFill->inheritsInternalColor()
? $this->fill->getForegroundColor()
: $eyeFill->getInternalColor());

$externalColor = $this->getColor($eyeFill->inheritsExternalColor()
? $this->fill->getForegroundColor()
: $eyeFill->getExternalColor());

for ($y = 0; $y < 7; $y += 1) {
for ($x = 0; $x < 7; $x += 1) {
if ((($y === 1 || $y === 5) && $x > 0 && $x < 6) || (($x === 1 || $x === 5) && $y > 0 && $y < 6)) {
continue;
}

$points = $this->normalizePoints([
($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset) * $pointInPx,
($this->margin + $x + $xOffset + 1) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
($this->margin + $x + $xOffset) * $pointInPx, ($this->margin + $y + $yOffset + 1) * $pointInPx,
]);

if ($y > 1 && $y < 5 && $x > 1 && $x < 5) {
imagefilledpolygon($this->image, $points, $internalColor);
} else {
imagefilledpolygon($this->image, $points, $externalColor);
}
}
}
}

/**
* Normalize points will trim right and bottom line by 1 pixel.
* Otherwise pixels of neighbors are overlapping which leads to issue with transparency and small QR codes.
*/
private function normalizePoints(array $points): array
{
$maxX = $maxY = 0;
for ($i = 0; $i < count($points); $i += 2) {
// Do manual round as GD just removes decimal part
$points[$i] = $newX = round($points[$i]);
$points[$i + 1] = $newY = round($points[$i + 1]);

$maxX = max($maxX, $newX);
$maxY = max($maxY, $newY);
}

// Do trimming only if there are 4 points (8 coordinates), assumes this is square.

for ($i = 0; $i < count($points); $i += 2) {
$points[$i] = min($points[$i], $maxX - 1);
$points[$i + 1] = min($points[$i + 1], $maxY - 1);
}

return $points;
}

private function renderImage(): string
{
ob_start();
$quality = $this->compressionQuality;
switch ($this->imageFormat) {
case 'png':
if ($quality > 9 || $quality < 0) {
$quality = 9;
}
imagepng($this->image, null, $quality);
break;

case 'gif':
imagegif($this->image, null);
break;

case 'jpeg':
case 'jpg':
if ($quality > 100 || $quality < 0) {
$quality = 85;
}
imagejpeg($this->image, null, $quality);
break;
default:
ob_end_clean();
throw new InvalidArgumentException(
'Supported image formats are jpeg, png and gif, got: ' . $this->imageFormat
);
}

imagedestroy($this->image);
$this->colors = [];
$this->image = null;

return ob_get_clean();
}

private function getColor(ColorInterface $color): int
{
$alpha = 100;

if ($color instanceof Alpha) {
$alpha = $color->getAlpha();
$color = $color->getBaseColor();
}

$rgb = $color->toRgb();

$colorKey = sprintf('%02X%02X%02X%02X', $rgb->getRed(), $rgb->getGreen(), $rgb->getBlue(), $alpha);

if (! isset($this->colors[$colorKey])) {
$colorId = imagecolorallocatealpha(
$this->image,
$rgb->getRed(),
$rgb->getGreen(),
$rgb->getBlue(),
(int)((100 - $alpha) / 100 * 127) // Alpha for GD is in range 0 (opaque) - 127 (transparent)
);

if ($colorId === false) {
throw new RuntimeException('Failed to create color: #' . $colorKey);
}

$this->colors[$colorKey] = $colorId;
}

return $this->colors[$colorKey];
}
}
71 changes: 71 additions & 0 deletions lib/vendor/robthree/twofactorauth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# RobThree\TwoFactorAuth changelog

# Version 3.x

## Breaking changes

### PHP Version

Version 3.x requires at least PHP 8.2.

### Constructor signature change

In order to ensure users of this library make a conscious choice of QR Code Provider, the QR Code Provider is now a mandatory argument, in first place.

If you didn't provide one explicitly before, you can get the old behavior with:

~~~php
use RobThree\Auth\TwoFactorAuth;
use RobThree\Auth\Providers\Qr\QRServerProvider;
$tfa = new TwoFactorAuth(new QRServerProvider());
~~~

If you provided one before, the order of the parameters have been changed, so simply move the QRCodeProvider argument to the first place or use named arguments.

Documentation on selecting a QR Code Provider is available here: [QR Code Provider documentation](https://robthree.github.io/TwoFactorAuth/qr-codes.html).

### Default secret length

The default secret length has been increased from 80 bits to 160 bits (RFC4226) PR [#117](https://github.com/RobThree/TwoFactorAuth/pull/117). This might cause an issue in your application if you were previously storing secrets in a column with restricted size. This change doesn't impact existing secrets, only new ones will get longer.

Previously a secret was 16 characters, now it needs to be stored in a 32 characters width column.

You can keep the old behavior by setting `80` as argument to `createSecret()` (not recommended, see [#117](https://github.com/RobThree/TwoFactorAuth/pull/117) for further discussion).

## Other changes

* The new PHP attribute [SensitiveParameter](https://www.php.net/manual/en/class.sensitiveparameter.php) was added to the code, to prevent accidental leak of secrets in stack traces.
* Likely not breaking anything, but now all external QR Code providers use HTTPS with a verified certificate. PR [#126](https://github.com/RobThree/TwoFactorAuth/pull/126).
* The CSPRNG is now exclusively using `random_bytes()` PHP function. Previously a fallback to `openssl` or non cryptographically secure PRNG existed, they have been removed. PR [#122](https://github.com/RobThree/TwoFactorAuth/pull/122).
* If an external QR code provider is used and the HTTP request results in an error, it will throw a `QRException`. Previously the error was ignored. PR [#130](https://github.com/RobThree/TwoFactorAuth/pull/130), fixes [#129](https://github.com/RobThree/TwoFactorAuth/issues/129).

# Version 2.x

## Breaking changes

### PHP Version

Version 2.x requires at least PHP 8.1.

### Constructor signature

With version 2.x, the `algorithm` parameter of `RobThree\Auth\TwoFactorAuth` constructor is now an `enum`.

On version 1.x:

~~~php
use RobThree\Auth\TwoFactorAuth;

$lib = new TwoFactorAuth('issuer-name', 6, 30, 'sha1');
~~~

On version 2.x, simple change the algorithm from a `string` to the correct `enum`:

~~~php
use RobThree\Auth\TwoFactorAuth;
use RobThree\Auth\Algorithm;

$lib = new TwoFactorAuth('issuer-name', 6, 30, Algorithm::Sha1);
~~~

See the [Algorithm.php](./lib/Algorithm.php) file to see available algorithms.
16 changes: 16 additions & 0 deletions lib/vendor/robthree/twofactorauth/lib/Algorithm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace RobThree\Auth;

/**
* List of supported cryptographic algorithms
*/
enum Algorithm: string
{
case Md5 = 'md5';
case Sha1 = 'sha1';
case Sha256 = 'sha256';
case Sha512 = 'sha512';
}

0 comments on commit 43dc722

Please sign in to comment.