Skip to content

Commit

Permalink
DI extensions: are using configuration Schema
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Apr 1, 2019
1 parent 76ad266 commit 8fd7f28
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 52 deletions.
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
"nette/tester": "^2.0",
"tracy/tracy": "^2.4"
},
"conflict": {
"nette/di": "<3.0"
},
"suggest": {
"ext-fileinfo": "to detect type of uploaded files",
"nette/security": "allows use Nette\\Http\\UserStorage"
Expand Down
57 changes: 31 additions & 26 deletions src/Bridges/HttpDI/HttpExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,14 @@

use Nette;
use Nette\PhpGenerator\Helpers;
use Nette\Schema\Expect;


/**
* HTTP extension for Nette DI.
*/
class HttpExtension extends Nette\DI\CompilerExtension
{
public $defaults = [
'proxy' => [],
'headers' => [
'X-Powered-By' => 'Nette Framework 3',
'Content-Type' => 'text/html; charset=utf-8',
],
'frames' => 'SAMEORIGIN', // X-Frame-Options
'csp' => [], // Content-Security-Policy
'cspReportOnly' => [], // Content-Security-Policy-Report-Only
'featurePolicy' => [], // Feature-Policy
'cookieSecure' => 'auto', // true|false|auto Whether the cookie is available only through HTTPS
];

/** @var bool */
private $cliMode;

Expand All @@ -41,25 +29,42 @@ public function __construct(bool $cliMode = false)
}


public function getConfigSchema(): Nette\Schema\Schema
{
return Expect::structure([
'proxy' => Expect::arrayOf('string')->dynamic(),
'headers' => Expect::arrayOf('scalar|null')->default([
'X-Powered-By' => 'Nette Framework 3',
'Content-Type' => 'text/html; charset=utf-8',
]),
'frames' => Expect::enum(Expect::string('SAMEORIGIN'), Expect::bool(), null), // X-Frame-Options
'csp' => Expect::arrayOf('array|scalar|null'), // Content-Security-Policy
'cspReportOnly' => Expect::arrayOf('array|scalar|null'), // Content-Security-Policy-Report-Only
'featurePolicy' => Expect::arrayOf('array|scalar|null'), // Feature-Policy
'cookieSecure' => Expect::enum(null, true, false, 'auto'), // true|false|auto Whether the cookie is available only through HTTPS
]);
}


public function loadConfiguration()
{
$builder = $this->getContainerBuilder();
$config = $this->validateConfig($this->defaults);
$config = $this->config;

$builder->addDefinition($this->prefix('requestFactory'))
->setFactory(Nette\Http\RequestFactory::class)
->addSetup('setProxy', [$config['proxy']]);
->addSetup('setProxy', [$config->proxy]);

$builder->addDefinition($this->prefix('request'))
->setFactory('@Nette\Http\RequestFactory::createHttpRequest');

$response = $builder->addDefinition($this->prefix('response'))
->setFactory(Nette\Http\Response::class);

if (isset($config['cookieSecure'])) {
$value = $config['cookieSecure'] === 'auto'
if ($config->cookieSecure !== null) {
$value = $config->cookieSecure === 'auto'
? $builder::literal('$this->getService(?)->isSecured()', [$this->prefix('request')])
: (bool) $config['cookieSecure'];
: $config->cookieSecure;
$response->addSetup('$cookieSecure', [$value]);
}

Expand All @@ -78,11 +83,11 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
}

$initialize = $class->getMethod('initialize');
$config = $this->getConfig();
$headers = array_map('strval', $config['headers']);
$config = $this->config;
$headers = array_map('strval', $config->headers);

if (isset($config['frames']) && $config['frames'] !== true && !isset($headers['X-Frame-Options'])) {
$frames = $config['frames'];
if (isset($config->frames) && $config->frames !== true && !isset($headers['X-Frame-Options'])) {
$frames = $config->frames;
if ($frames === false) {
$frames = 'DENY';
} elseif (preg_match('#^https?:#', $frames)) {
Expand All @@ -93,10 +98,10 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)

$code = [];
foreach (['csp', 'cspReportOnly'] as $key) {
if (empty($config[$key])) {
if (empty($config->$key)) {
continue;
}
$value = self::buildPolicy($config[$key]);
$value = self::buildPolicy($config->$key);
if (strpos($value, "'nonce'")) {
$code[0] = '$cspNonce = base64_encode(random_bytes(16));';
$value = Nette\DI\ContainerBuilder::literal(
Expand All @@ -107,8 +112,8 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
$headers['Content-Security-Policy' . ($key === 'csp' ? '' : '-Report-Only')] = $value;
}

if (!empty($config['featurePolicy'])) {
$headers['Feature-Policy'] = self::buildPolicy($config['featurePolicy']);
if (!empty($config->featurePolicy)) {
$headers['Feature-Policy'] = self::buildPolicy($config->featurePolicy);
}

$code[] = Helpers::formatArgs('$response = $this->getService(?);', [$this->prefix('response')]);
Expand Down
56 changes: 30 additions & 26 deletions src/Bridges/HttpDI/SessionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,14 @@
namespace Nette\Bridges\HttpDI;

use Nette;
use Nette\Schema\Expect;


/**
* Session extension for Nette DI.
*/
class SessionExtension extends Nette\DI\CompilerExtension
{
public $defaults = [
'debugger' => false,
'autoStart' => 'smart', // true|false|smart
'expiration' => null,
'handler' => null,
];

/** @var bool */
private $debugMode;

Expand All @@ -38,40 +32,51 @@ public function __construct(bool $debugMode = false, bool $cliMode = false)
}


public function getConfigSchema(): Nette\Schema\Schema
{
return Expect::structure([
'debugger' => Expect::bool(false),
'autoStart' => Expect::enum('smart', true, false)->default('smart'),
'expiration' => Expect::string()->dynamic(),
'handler' => Expect::string()->dynamic(),
])->otherItems('mixed');
}


public function loadConfiguration()
{
$builder = $this->getContainerBuilder();
$config = $this->getConfig() + $this->defaults;
$this->setConfig($config);
$config = $this->config;

$session = $builder->addDefinition($this->prefix('session'))
->setFactory(Nette\Http\Session::class);

if ($config['expiration']) {
$session->addSetup('setExpiration', [$config['expiration']]);
if ($config->expiration) {
$session->addSetup('setExpiration', [$config->expiration]);
}
if ($config['handler']) {
$session->addSetup('setHandler', [$config['handler']]);
if ($config->handler) {
$session->addSetup('setHandler', [$config->handler]);
}
if (($config['cookieDomain'] ?? null) === 'domain') {
$config['cookieDomain'] = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->getUrl()->getDomain(2)');
if (($config->cookieDomain ?? null) === 'domain') {
$config->cookieDomain = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->getUrl()->getDomain(2)');
}
if (($config['cookieSecure'] ?? null) === 'auto') {
$config['cookieSecure'] = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->isSecured()');
if (($config->cookieSecure ?? null) === 'auto') {
$config->cookieSecure = $builder::literal('$this->getByType(Nette\Http\IRequest::class)->isSecured()');
}
if (($config['cookieSamesite'] ?? null) === true) {
$config['cookieSamesite'] = 'Lax';
if (($config->cookieSamesite ?? null) === true) {
$config->cookieSamesite = 'Lax';
}

if ($this->debugMode && $config['debugger']) {
if ($this->debugMode && $config->debugger) {
$session->addSetup('@Tracy\Bar::addPanel', [
new Nette\DI\Definitions\Statement(Nette\Bridges\HttpTracy\SessionPanel::class),
]);
}

unset($config['expiration'], $config['handler'], $config['autoStart'], $config['debugger']);
if (!empty($config)) {
$session->addSetup('setOptions', [$config]);
$options = (array) $config;
unset($options['expiration'], $options['handler'], $options['autoStart'], $options['debugger']);
if (!empty($options)) {
$session->addSetup('setOptions', [$options]);
}

if ($this->name === 'session') {
Expand All @@ -87,13 +92,12 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
}

$initialize = $class->getMethod('initialize');
$config = $this->getConfig();
$name = $this->prefix('session');

if ($config['autoStart'] === 'smart') {
if ($this->config->autoStart === 'smart') {
$initialize->addBody('$this->getService(?)->exists() && $this->getService(?)->start();', [$name, $name]);

} elseif ($config['autoStart']) {
} elseif ($this->config->autoStart) {
$initialize->addBody('$this->getService(?)->start();', [$name]);
}
}
Expand Down

0 comments on commit 8fd7f28

Please sign in to comment.