Skip to content

Commit

Permalink
Merge pull request #1917 from nextcloud/ocjs_inline
Browse files Browse the repository at this point in the history
Inline oc.js when possible!
  • Loading branch information
MorrisJobke authored Oct 25, 2016
2 parents 1b6ba5a + 015affb commit 9a70c13
Show file tree
Hide file tree
Showing 15 changed files with 426 additions and 32 deletions.
92 changes: 92 additions & 0 deletions core/Controller/OCJSController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OC\Core\Controller;

use bantu\IniGetWrapper\IniGetWrapper;
use OC\Template\JSConfigHelper;
use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserSession;

class OCJSController extends Controller {

/** @var JSConfigHelper */
private $helper;

/**
* OCJSController constructor.
*
* @param string $appName
* @param IRequest $request
* @param IL10N $l
* @param \OC_Defaults $defaults
* @param IAppManager $appManager
* @param IUserSession $session
* @param IConfig $config
* @param IGroupManager $groupManager
* @param IniGetWrapper $iniWrapper
* @param IURLGenerator $urlGenerator
*/
public function __construct($appName,
IRequest $request,
IL10N $l,
\OC_Defaults $defaults,
IAppManager $appManager,
IUserSession $session,
IConfig $config,
IGroupManager $groupManager,
IniGetWrapper $iniWrapper,
IURLGenerator $urlGenerator) {
parent::__construct($appName, $request);

$this->helper = new JSConfigHelper(
$l,
$defaults,
$appManager,
$session->getUser(),
$config,
$groupManager,
$iniWrapper,
$urlGenerator
);
}

/**
* @NoCSRFRequired
* @PublicPage
*
* @return DataDisplayResponse
*/
public function getConfig() {
$data = $this->helper->getConfig();

return new DataDisplayResponse($data, Http::STATUS_OK, ['Content-type' => 'text/javascript']);
}
}
4 changes: 1 addition & 3 deletions core/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
['name' => 'TwoFactorChallenge#selectChallenge', 'url' => '/login/selectchallenge', 'verb' => 'GET'],
['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'],
['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'],
['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'],
],
'ocs' => [
['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
Expand All @@ -66,9 +67,6 @@
// Search
$this->create('search_ajax_search', '/core/search')
->actionInclude('core/search/ajax/search.php');
// oC JS config
$this->create('js_config', '/core/js/oc.js')
->actionInclude('core/js/config.php');
// Routing
$this->create('core_ajax_preview', '/core/preview')
->actionInclude('core/ajax/preview.php');
Expand Down
5 changes: 5 additions & 0 deletions core/templates/layout.base.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach ($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
Expand Down
5 changes: 5 additions & 0 deletions core/templates/layout.guest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
Expand Down
5 changes: 5 additions & 0 deletions core/templates/layout.user.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
<?php foreach($_['printcssfiles'] as $cssfile): ?>
<link rel="stylesheet" href="<?php print_unescaped($cssfile); ?>" media="print">
<?php endforeach; ?>
<?php if (isset($_['inline_ocjs'])): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" type="text/javascript">
<?php print_unescaped($_['inline_ocjs']); ?>
</script>
<?php endif; ?>
<?php foreach($_['jsfiles'] as $jsfile): ?>
<script nonce="<?php p(\OC::$server->getContentSecurityPolicyNonceManager()->getNonce()) ?>" src="<?php print_unescaped($jsfile); ?>"></script>
<?php endforeach; ?>
Expand Down
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@
'OC\\Core\\Controller\\AvatarController' => $baseDir . '/core/Controller/AvatarController.php',
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php',
'OC\\Core\\Controller\\OCJSController' => $baseDir . '/core/Controller/OCJSController.php',
'OC\\Core\\Controller\\OCSController' => $baseDir . '/core/Controller/OCSController.php',
'OC\\Core\\Controller\\SetupController' => $baseDir . '/core/Controller/SetupController.php',
'OC\\Core\\Controller\\TwoFactorChallengeController' => $baseDir . '/core/Controller/TwoFactorChallengeController.php',
Expand Down Expand Up @@ -752,6 +753,7 @@
'OC\\TemplateLayout' => $baseDir . '/lib/private/TemplateLayout.php',
'OC\\Template\\Base' => $baseDir . '/lib/private/Template/Base.php',
'OC\\Template\\CSSResourceLocator' => $baseDir . '/lib/private/Template/CSSResourceLocator.php',
'OC\\Template\\JSConfigHelper' => $baseDir . '/lib/private/Template/JSConfigHelper.php',
'OC\\Template\\JSResourceLocator' => $baseDir . '/lib/private/Template/JSResourceLocator.php',
'OC\\Template\\ResourceLocator' => $baseDir . '/lib/private/Template/ResourceLocator.php',
'OC\\Template\\ResourceNotFoundException' => $baseDir . '/lib/private/Template/ResourceNotFoundException.php',
Expand Down
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Controller\\AvatarController' => __DIR__ . '/../../..' . '/core/Controller/AvatarController.php',
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php',
'OC\\Core\\Controller\\OCJSController' => __DIR__ . '/../../..' . '/core/Controller/OCJSController.php',
'OC\\Core\\Controller\\OCSController' => __DIR__ . '/../../..' . '/core/Controller/OCSController.php',
'OC\\Core\\Controller\\SetupController' => __DIR__ . '/../../..' . '/core/Controller/SetupController.php',
'OC\\Core\\Controller\\TwoFactorChallengeController' => __DIR__ . '/../../..' . '/core/Controller/TwoFactorChallengeController.php',
Expand Down Expand Up @@ -782,6 +783,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\TemplateLayout' => __DIR__ . '/../../..' . '/lib/private/TemplateLayout.php',
'OC\\Template\\Base' => __DIR__ . '/../../..' . '/lib/private/Template/Base.php',
'OC\\Template\\CSSResourceLocator' => __DIR__ . '/../../..' . '/lib/private/Template/CSSResourceLocator.php',
'OC\\Template\\JSConfigHelper' => __DIR__ . '/../../..' . '/lib/private/Template/JSConfigHelper.php',
'OC\\Template\\JSResourceLocator' => __DIR__ . '/../../..' . '/lib/private/Template/JSResourceLocator.php',
'OC\\Template\\ResourceLocator' => __DIR__ . '/../../..' . '/lib/private/Template/ResourceLocator.php',
'OC\\Template\\ResourceNotFoundException' => __DIR__ . '/../../..' . '/lib/private/Template/ResourceNotFoundException.php',
Expand Down
3 changes: 2 additions & 1 deletion lib/private/AppFramework/DependencyInjection/DIContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ public function __construct($appName, $urlParams = array()){
$app->isLoggedIn(),
$app->isAdminUser(),
$app->getServer()->getContentSecurityPolicyManager(),
$app->getServer()->getCsrfTokenManager()
$app->getServer()->getCsrfTokenManager(),
$app->getServer()->getContentSecurityPolicyNonceManager()
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use OC\AppFramework\Middleware\Security\Exceptions\StrictCookieMissingException;
use OC\AppFramework\Utility\ControllerMethodReflector;
use OC\Security\CSP\ContentSecurityPolicyManager;
use OC\Security\CSP\ContentSecurityPolicyNonceManager;
use OC\Security\CSRF\CsrfTokenManager;
use OCP\AppFramework\Http\ContentSecurityPolicy;
use OCP\AppFramework\Http\EmptyContentSecurityPolicy;
Expand Down Expand Up @@ -80,6 +81,8 @@ class SecurityMiddleware extends Middleware {
private $contentSecurityPolicyManager;
/** @var CsrfTokenManager */
private $csrfTokenManager;
/** @var ContentSecurityPolicyNonceManager */
private $cspNonceManager;

/**
* @param IRequest $request
Expand All @@ -92,6 +95,7 @@ class SecurityMiddleware extends Middleware {
* @param bool $isAdminUser
* @param ContentSecurityPolicyManager $contentSecurityPolicyManager
* @param CSRFTokenManager $csrfTokenManager
* @param ContentSecurityPolicyNonceManager $cspNonceManager
*/
public function __construct(IRequest $request,
ControllerMethodReflector $reflector,
Expand All @@ -102,7 +106,8 @@ public function __construct(IRequest $request,
$isLoggedIn,
$isAdminUser,
ContentSecurityPolicyManager $contentSecurityPolicyManager,
CsrfTokenManager $csrfTokenManager) {
CsrfTokenManager $csrfTokenManager,
ContentSecurityPolicyNonceManager $cspNonceManager) {
$this->navigationManager = $navigationManager;
$this->request = $request;
$this->reflector = $reflector;
Expand All @@ -113,6 +118,7 @@ public function __construct(IRequest $request,
$this->isAdminUser = $isAdminUser;
$this->contentSecurityPolicyManager = $contentSecurityPolicyManager;
$this->csrfTokenManager = $csrfTokenManager;
$this->cspNonceManager = $cspNonceManager;
}


Expand Down Expand Up @@ -177,23 +183,6 @@ public function beforeController($controller, $methodName) {

}

private function browserSupportsCspV3() {
$browserWhitelist = [
// Chrome 40+
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/',
// Firefox 45+
'/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/',
// Safari 10+
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/',
];

if($this->request->isUserAgent($browserWhitelist)) {
return true;
}

return false;
}

/**
* Performs the default CSP modifications that may be injected by other
* applications
Expand All @@ -213,7 +202,7 @@ public function afterController($controller, $methodName, Response $response) {
$defaultPolicy = $this->contentSecurityPolicyManager->getDefaultPolicy();
$defaultPolicy = $this->contentSecurityPolicyManager->mergePolicies($defaultPolicy, $policy);

if($this->browserSupportsCspV3()) {
if($this->cspNonceManager->browserSupportsCspV3()) {
$defaultPolicy->useJsNonce($this->csrfTokenManager->getToken()->getEncryptedValue());
}

Expand Down
30 changes: 29 additions & 1 deletion lib/private/Security/CSP/ContentSecurityPolicyNonceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,27 @@
namespace OC\Security\CSP;

use OC\Security\CSRF\CsrfTokenManager;
use OCP\IRequest;

/**
* @package OC\Security\CSP
*/
class ContentSecurityPolicyNonceManager {
/** @var CsrfTokenManager */
private $csrfTokenManager;
/** @var IRequest */
private $request;
/** @var string */
private $nonce = '';

/**
* @param CsrfTokenManager $csrfTokenManager
* @param IRequest $request
*/
public function __construct(CsrfTokenManager $csrfTokenManager) {
public function __construct(CsrfTokenManager $csrfTokenManager,
IRequest $request) {
$this->csrfTokenManager = $csrfTokenManager;
$this->request = $request;
}

/**
Expand All @@ -51,4 +57,26 @@ public function getNonce() {

return $this->nonce;
}

/**
* Check if the browser supports CSP v3
*
* @return bool
*/
public function browserSupportsCspV3() {
$browserWhitelist = [
// Chrome 40+
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[4-9][0-9].[0-9.]+ (Mobile Safari|Safari)\/[0-9.]+$/',
// Firefox 45+
'/^Mozilla\/5\.0 \([^)]+\) Gecko\/[0-9.]+ Firefox\/(4[5-9]|[5-9][0-9])\.[0-9.]+$/',
// Safari 10+
'/^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Version\/1[0-9.]+ Safari\/[0-9.A-Z]+$/',
];

if($this->request->isUserAgent($browserWhitelist)) {
return true;
}

return false;
}
}
3 changes: 2 additions & 1 deletion lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,8 @@ public function __construct($webRoot, \OC\Config $config) {
});
$this->registerService('ContentSecurityPolicyNonceManager', function(Server $c) {
return new ContentSecurityPolicyNonceManager(
$c->getCsrfTokenManager()
$c->getCsrfTokenManager(),
$c->getRequest()
);
});
$this->registerService('ShareManager', function(Server $c) {
Expand Down
Loading

0 comments on commit 9a70c13

Please sign in to comment.