Skip to content

Commit

Permalink
fix: Adjust composer requirements and build matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
stephanschuler authored and paxuclus committed Oct 24, 2023
1 parent 45f1846 commit 691386f
Show file tree
Hide file tree
Showing 19 changed files with 715 additions and 52 deletions.
26 changes: 2 additions & 24 deletions .github/workflows/functionaltests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,8 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: [ 7.2, 7.3, 7.4, 8.0, 8.1 ]
flow-version: [ 5.3, 6.3, 7.3, 8.0 ]
exclude:
# Disable Flow 5.3 and 6.3 on PHP 8.0, as only ^7.2 is supported
- php-version: 8.0
flow-version: 5.3
- php-version: 8.0
flow-version: 6.3
- php-version: 8.1
flow-version: 5.3
- php-version: 8.1
flow-version: 6.3

# Disable Flow 7.0 on PHP 7.2, as 7.3 is required
- php-version: 7.2
flow-version: 7.3

# Disable Flow 8.0 on PHP 7, as 8.0 is required
- php-version: 7.2
flow-version: 8.0
- php-version: 7.3
flow-version: 8.0
- php-version: 7.4
flow-version: 8.0
php-version: [ 7.2, 7.3, 7.4 ]
flow-version: [ 5.3, 6.3 ]

env:
APP_ENV: true
Expand Down
26 changes: 2 additions & 24 deletions .github/workflows/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,8 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: [ 7.2, 7.3, 7.4, 8.0, 8.1 ]
flow-version: [ 5.3, 6.3, 7.3, 8.0 ]
exclude:
# Disable Flow 5.3 and 6.3 on PHP 8.0, as only ^7.2 is supported
- php-version: 8.0
flow-version: 5.3
- php-version: 8.0
flow-version: 6.3
- php-version: 8.1
flow-version: 5.3
- php-version: 8.1
flow-version: 6.3

# Disable Flow 7.0 on PHP 7.2, as 7.3 is required
- php-version: 7.2
flow-version: 7.3

# Disable Flow 8.0 on PHP 7, as 8.0 is required
- php-version: 7.2
flow-version: 8.0
- php-version: 7.3
flow-version: 8.0
- php-version: 7.4
flow-version: 8.0
php-version: [ 7.2, 7.3, 7.4 ]
flow-version: [ 5.3, 6.3 ]

env:
APP_ENV: true
Expand Down
43 changes: 43 additions & 0 deletions Classes/Controller/EncryptedPayloadController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Netlogix\Sentry\Controller;

use function json_decode;
use function json_encode;
use const JSON_PRETTY_PRINT;
use Neos\Flow\Mvc\Controller\ActionController;
use Netlogix\Sentry\Encryption\EncryptionService;
use Netlogix\Sentry\Encryption\Sealed;

class EncryptedPayloadController extends ActionController
{
protected EncryptionService $encryptionService;

public function injectEncryptionService(EncryptionService $encryptionService): void
{
$this->encryptionService = $encryptionService;
}

/**
* @param string $encryptedData
* @param string $initializationVector
* @param string $envelopeKey
*/
public function decryptAction(
string $encryptedData,
string $initializationVector,
string $envelopeKey
): string {
$sealed = Sealed::fromArray([
'encryptedData' => $encryptedData,
'initializationVector' => $initializationVector,
'envelopeKey' => $envelopeKey,
]);
$unencrypted = $this->encryptionService->open($sealed);
$this->response->setContentType('application/json');

return json_encode(json_decode($unencrypted, true), JSON_PRETTY_PRINT);
}
}
114 changes: 114 additions & 0 deletions Classes/Encryption/EncryptionService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace Netlogix\Sentry\Encryption;

use function http_build_query;
use Neos\Flow\Http\BaseUriProvider;
use Neos\Flow\Security\Cryptography\RsaWalletServiceInterface;
use Neos\Flow\Security\Cryptography\RsaWalletServicePhp;
use Neos\Flow\Security\Exception\InvalidKeyPairIdException;
use Neos\Utility\ObjectAccess;
use function openssl_open;
use function openssl_random_pseudo_bytes;
use function openssl_seal;
use Psr\Http\Message\UriInterface;

class EncryptionService
{
private const ALGORITHM = 'AES256';

private string $rsaKeyFingerprint;

private string $encryptionModuleUri;

private RsaWalletServiceInterface $rsaWallet;

private BaseUriProvider $baseUriProvider;

public function injectSettings(array $settings): void
{
$privacyCettings = $settings['privacy'] ?? [];
$this->rsaKeyFingerprint = (string) ($privacyCettings['rsaKeyFingerprint'] ?? '');
$this->encryptionModuleUri = (string) ($privacyCettings['encryptionModuleUri'] ?? '');
}

public function injectRsaWalletService(RsaWalletServiceInterface $rsaWallet): void
{
$this->rsaWallet = $rsaWallet;
}

public function injectBaseUriProvider(BaseUriProvider $baseUriProvider): void
{
$this->baseUriProvider = $baseUriProvider;
}

public function seal(string $unencryptedData): Sealed
{
$publicKeyString = $this->getKeyString('publicKey');

$initializationVector = openssl_random_pseudo_bytes(32);

openssl_seal(
$unencryptedData,
$encryptedData,
$envelopeKeys,
[$publicKeyString],
self::ALGORITHM,
$initializationVector
);

return new Sealed($encryptedData, $initializationVector, $envelopeKeys[0]);
}

public function open(Sealed $package): string
{
$privateKeyString = $this->getKeyString('privateKey');

$encryptedData = $package->getEncryptedData();
$envelopeKey = $package->getEnvelopeKey();
$initializationVector = $package->getInitializationVector();

openssl_open(
$encryptedData,
$unencryptedData,
$envelopeKey,
$privateKeyString,
self::ALGORITHM,
$initializationVector
);

return $unencryptedData;
}

public function getEncryptionUriForSealedPayload(Sealed $sealed): UriInterface
{
return $this->baseUriProvider
->getConfiguredBaseUriOrFallbackToCurrentRequest()
->withPath($this->encryptionModuleUri)
->withQuery(http_build_query($sealed->toArray()));
}

/**
* @param 'privateKey' | 'publicKey' $slotName
*/
private function getKeyString(string $slotName): string
{
assert($this->rsaWallet instanceof RsaWalletServicePhp);
// Prime key pair, male rsaWallet load the key pair
$this->rsaWallet->getPublicKey($this->rsaKeyFingerprint);
// Private property
$keys = ObjectAccess::getProperty($this->rsaWallet, 'keys', true);
// Property path in plain array
$keyString = ObjectAccess::getPropertyPath(
$keys,
sprintf('%s.%s.keyString', $this->rsaKeyFingerprint, $slotName)
);
if (!\is_string($keyString)) {
throw new InvalidKeyPairIdException('Invalid key fingerprint given', 1693231337);
}

return $keyString;
}
}
61 changes: 61 additions & 0 deletions Classes/Encryption/Sealed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Netlogix\Sentry\Encryption;

use function base64_decode;
use function base64_encode;
use Neos\Flow\Annotations as Flow;

/**
* @Flow\Proxy(false)
*/
final class Sealed
{
private string $encryptedData;

private string $initializationVector;

private string $envelopeKey;

public function __construct(string $encryptedData, string $initializationVector, string $envelopeKeys)
{
$this->encryptedData = $encryptedData;
$this->initializationVector = $initializationVector;
$this->envelopeKey = $envelopeKeys;
}

public static function fromArray(array $package): self
{
return new self(
$package['encryptedData'] ? base64_decode($package['encryptedData'], true) : '',
$package['initializationVector'] ? base64_decode($package['initializationVector'], true) : '',
$package['envelopeKey'] ? base64_decode($package['envelopeKey'], true) : ''
);
}

public function toArray(): array
{
return [
'encryptedData' => base64_encode($this->encryptedData),
'initializationVector' => base64_encode($this->initializationVector),
'envelopeKey' => base64_encode($this->envelopeKey),
];
}

public function getEncryptedData(): string
{
return $this->encryptedData;
}

public function getInitializationVector(): string
{
return $this->initializationVector;
}

public function getEnvelopeKey(): string
{
return $this->envelopeKey;
}
}
64 changes: 64 additions & 0 deletions Classes/EventProcessor/EncryptedPayload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace Netlogix\Sentry\EventProcessor;

use function json_encode;
use Neos\Flow\Annotations as Flow;
use Netlogix\Sentry\Encryption\EncryptionService;
use Sentry\Event;
use Sentry\EventHint;

/**
* @Flow\Scope("singleton")
*/
final class EncryptedPayload implements EventProcessor
{
private EncryptionService $encryption;

private bool $encryptPostBody;

public function injectEncryptionService(EncryptionService $encryption): void
{
$this->encryption = $encryption;
}

public function injectSettings(array $settings): void
{
$privacyCettings = $settings['privacy'] ?? [];
$this->encryptPostBody = (bool) ($privacyCettings['encryptPostBody'] ?? false);
}

public function rewriteEvent(Event $event, EventHint $hint): Event
{
if (!$this->encryptPostBody) {
return $event;
}

$request = $event->getRequest();

$data = $request['data'] ?? [];
if (!$data || !is_array($data)) {
return $event;
}

$unencrypted = (string) json_encode($data, \JSON_PRETTY_PRINT);

$encrypted = $this->encryption
->seal($unencrypted);
$uri = (string) $this->encryption
->getEncryptionUriForSealedPayload($encrypted);

$request['data'] = [
'__ENCRYPTED__DATA__' => $encrypted->toArray(),
];
$event->setRequest($request);

$extra = $event->getExtra() ?? [];
$extra['Encrypted POST Data'] = $uri;
$event->setExtra($extra);

return $event;
}
}
13 changes: 13 additions & 0 deletions Classes/EventProcessor/EventProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Netlogix\Sentry\EventProcessor;

use Sentry\Event;
use Sentry\EventHint;

interface EventProcessor
{
public function rewriteEvent(Event $event, EventHint $hint): Event;
}
Loading

0 comments on commit 691386f

Please sign in to comment.