diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f1902667..80c66ae8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -* **Build 27x** (2015-06-xx) +* **Build 275** (2015-07-04) - List columns now support specifying a `default` option used when the value would otherwise be null. - Implement a custom autoloader for plugins that use composer. Now only one instance of composer is used, all packages are now added to a global pool to prevent double loading and the load order is respected. - The method signature of `Model::save()` has been fixed to match Eloquent. + - Added new security config option `cms.enableCsrfProtection`. * **Build 272** (2015-06-27) - Protected images and their thumbnails are now supported in the back-end. diff --git a/config/cms.php b/config/cms.php index 98bff8227..88ee86081 100644 --- a/config/cms.php +++ b/config/cms.php @@ -250,4 +250,16 @@ return [ 'defaultMask' => ['file' => null, 'folder' => null], + /* + |-------------------------------------------------------------------------- + | Cross Site Request Forgery (CSRF) Protection + |-------------------------------------------------------------------------- + | + | If the CSRF protection is enabled, all "postback" requests are checked + | for a valid security token. + | + */ + + 'enableCsrfProtection' => false, + ]; diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js index 9985a4ad6..ba43852de 100644 --- a/modules/backend/assets/js/october-min.js +++ b/modules/backend/assets/js/october-min.js @@ -2663,8 +2663,10 @@ this.escape() $(document).off('focusin.bs.modal') this.$element.removeClass('in').attr('aria-hidden',true).off('click.dismiss.bs.modal') $.support.transition&&this.$element.hasClass('fade')?this.$element.one($.support.transition.end,$.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal()} -Modal.prototype.enforceFocus=function(){$(document).off('focusin.bs.modal').on('focusin.bs.modal',$.proxy(function(e){if(this.$element[0]!==e.target&&!this.$element.has(e.target).length){this.$element.focus()}},this))} -Modal.prototype.escape=function(){if(this.isShown&&this.options.keyboard){this.$element.on('keyup.dismiss.bs.modal',$.proxy(function(e){e.which==27&&this.hide()},this))}else if(!this.isShown){this.$element.off('keyup.dismiss.bs.modal')}} +Modal.prototype.enforceFocus=function(){$(document).off('focusin.bs.modal').on('focusin.bs.modal',$.proxy(function(e){if($(e.target).hasClass('select2-search__field')){return} +if(this.$element[0]!==e.target&&!this.$element.has(e.target).length){this.$element.focus()}},this))} +Modal.prototype.escape=function(){if(this.isShown&&this.options.keyboard){this.$element.on('keyup.dismiss.bs.modal',$.proxy(function(e){e.which==27&&this.hide()},this))} +else if(!this.isShown){this.$element.off('keyup.dismiss.bs.modal')}} Modal.prototype.hideModal=function(){var that=this this.$element.hide() this.backdrop(function(){that.removeBackdrop() @@ -2679,8 +2681,10 @@ this.options.backdrop=='static'?this.$element[0].focus.call(this.$element[0]):th if(doAnimate)this.$backdrop[0].offsetWidth this.$backdrop.addClass('in') if(!callback)return -doAnimate?this.$backdrop.one($.support.transition.end,callback).emulateTransitionEnd(150):callback()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass('in') -$.support.transition&&this.$element.hasClass('fade')?this.$backdrop.one($.support.transition.end,callback).emulateTransitionEnd(150):callback()}else if(callback){callback()}} +doAnimate?this.$backdrop.one($.support.transition.end,callback).emulateTransitionEnd(150):callback()} +else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass('in') +$.support.transition&&this.$element.hasClass('fade')?this.$backdrop.one($.support.transition.end,callback).emulateTransitionEnd(150):callback()} +else if(callback){callback()}} var old=$.fn.modal $.fn.modal=function(option,_relatedTarget){return this.each(function(){var $this=$(this) var data=$this.data('bs.modal') @@ -2715,9 +2719,11 @@ self.isOpen=false self.setBackdrop(false)}) this.$modal.on('hidden.bs.modal',function(){self.triggerEvent('hidden.oc.popup') self.$container.remove() -self.$el.data('oc.popup',null)}) +self.$el.data('oc.popup',null) +$(document.body).removeClass('modal-open')}) this.$modal.on('show.bs.modal',function(){self.isOpen=true -self.setBackdrop(true)}) +self.setBackdrop(true) +$(document.body).addClass('modal-open')}) this.$modal.on('shown.bs.modal',function(){self.triggerEvent('shown.oc.popup')}) this.$modal.on('close.oc.popup',function(){self.hide() return false}) diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index 5a0963960..cab4f1d0e 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -580,9 +580,11 @@ class RelationController extends ControllerBehavior $widget = $this->makeWidget('Backend\Widgets\Lists', $config); $widget->bindEvent('list.extendQuery', function ($query) { $this->controller->relationExtendQuery($query, $this->field); - $this->relationObject->setQuery($query); - if ($sessionKey = $this->relationGetSessionKey()) { + + $sessionKey = $this->deferredBinding ? $this->relationGetSessionKey() : null; + + if ($sessionKey) { $this->relationObject->withDeferred($sessionKey); } elseif ($this->model->exists) { diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index ebf0c1825..56d3770b4 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -6,6 +6,7 @@ use Lang; use View; use Flash; use Event; +use Config; use Request; use Backend; use Session; @@ -34,9 +35,9 @@ use Illuminate\Http\RedirectResponse; */ class Controller extends Extendable { + use \System\Traits\ViewMaker; use \System\Traits\AssetMaker; use \System\Traits\ConfigMaker; - use \System\Traits\ViewMaker; use \Backend\Traits\WidgetMaker; use \October\Rain\Support\Traits\Emitter; @@ -118,11 +119,6 @@ class Controller extends Extendable */ protected $statusCode = 200; - /** - * @var bool Determine if submission requests use CSRF protection. - */ - public $useSecurityToken = true; - /** * Constructor. */ @@ -176,7 +172,7 @@ class Controller extends Extendable /* * Check security token. */ - if ($this->useSecurityToken && !$this->verifyCsrfToken()) { + if (!$this->verifyCsrfToken()) { return Response::make(Lang::get('backend::lang.page.invalid_token.label'), 403); } @@ -629,11 +625,16 @@ class Controller extends Extendable /** * Checks the request data / headers for a valid CSRF token. - * Returns false if a valid token is not found. + * Returns false if a valid token is not found. Override this + * method to disable the check. * @return bool */ protected function verifyCsrfToken() { + if (!Config::get('cms.enableCsrfProtection')) { + return true; + } + if (in_array(Request::method(), ['HEAD', 'GET', 'OPTIONS'])) { return true; } diff --git a/modules/backend/controllers/usergroups/_list_toolbar.htm b/modules/backend/controllers/usergroups/_list_toolbar.htm index 4e33b1ed4..b1d2b38bc 100644 --- a/modules/backend/controllers/usergroups/_list_toolbar.htm +++ b/modules/backend/controllers/usergroups/_list_toolbar.htm @@ -1,3 +1,8 @@
- + + + + + +
diff --git a/modules/backend/controllers/users/_list_toolbar.htm b/modules/backend/controllers/users/_list_toolbar.htm index e18014386..69ff34f5e 100644 --- a/modules/backend/controllers/users/_list_toolbar.htm +++ b/modules/backend/controllers/users/_list_toolbar.htm @@ -1,6 +1,10 @@
- - + + + + + +