mirror of
https://github.com/getgrav/grav-plugin-admin.git
synced 2026-02-05 14:20:27 +01:00
Merge branch 'develop' into 1.9
# Conflicts: # languages/en.yaml # themes/grav/css-compiled/preset.css # themes/grav/css-compiled/preset.css.map # themes/grav/js/admin.min.js # themes/grav/js/vendor.min.js # themes/grav/scss/preset.scss
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,7 +6,7 @@ themes/grav/.sass-cache
|
||||
themes/grav/js/admin.js
|
||||
themes/grav/js/vendor.js
|
||||
themes/grav/js/*.map
|
||||
/.idea
|
||||
.idea
|
||||
|
||||
tests/_output/*
|
||||
tests/_support/_generated/*
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
## mm/dd/2018
|
||||
|
||||
1. [](#new)
|
||||
* IMPORTANT: Non `admin.super` users are now subject to XSS validation in Page content. Configurable via Configuration / Security
|
||||
* Added new event `onAdminPage` which allows plugins to customize `Page` object in `$event['page']`
|
||||
1. [](#improved)
|
||||
* Use `Url:post()` to get the `$_POST` variable (allows common security checks/filtering for the POST data)
|
||||
|
||||
@@ -611,6 +611,8 @@ class AdminController extends AdminBaseController
|
||||
$reorder = true;
|
||||
$data = (array)$this->data;
|
||||
|
||||
$this->grav['twig']->twig_vars['current_form_data'] = $data;
|
||||
|
||||
// Special handler for user data.
|
||||
if ($this->view === 'user') {
|
||||
if (!$this->grav['user']->exists()) {
|
||||
@@ -645,10 +647,20 @@ class AdminController extends AdminBaseController
|
||||
// Ensure route is prefixed with a forward slash.
|
||||
$route = '/' . ltrim($route, '/');
|
||||
|
||||
// XSS Checks for page content
|
||||
$xss_whitelist = $this->grav['config']->get('security.xss_whitelist', 'admin.super');
|
||||
if (!$this->admin->authorize($xss_whitelist)) {
|
||||
if ($issue = Utils::detectXss($data['content'])) {
|
||||
$this->admin->setMessage(sprintf($this->admin->translate('PLUGIN_ADMIN.XSS_ISSUE'), $issue),
|
||||
'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for valid frontmatter
|
||||
if (isset($data['frontmatter']) && !$this->checkValidFrontmatter($data['frontmatter'])) {
|
||||
$this->admin->setMessage($this->admin->translate('PLUGIN_ADMIN.INVALID_FRONTMATTER_COULD_NOT_SAVE'),
|
||||
'error');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -755,4 +755,14 @@ PLUGIN_ADMIN:
|
||||
SCHEDULER_POST_INSTRUCTIONS: "To enable the Scheduler's functionality, you must add the <b>Grav Scheduler</b> to your system's crontab file. Run the command above from the terminal to add it automatically. Once saved, refresh this page to see the status Ready."
|
||||
SCHEDULER_JOBS: "Custom Scheduler Jobs"
|
||||
SCHEDULER_STATUS: "Scheduler Status"
|
||||
SECURITY: "Security"
|
||||
XSS_SECURITY: "XSS Security"
|
||||
XSS_WHITELIST_PERMISSIONS: "Whitelist Permissions"
|
||||
XSS_WHITELIST_PERMISSIONS_HELP: "Users with these permissions will skip the XSS rules when saving content"
|
||||
XSS_RULES: "Rules"
|
||||
XSS_RULES_HELP: "Be careful when tweaking these rules, a broken regex will break things badly!"
|
||||
XSS_RULE_LABEL: "Label"
|
||||
XSS_RULE_REGEX: "Regex"
|
||||
XSS_ISSUE: "Save failed: Found potential XSS code of type: <strong>%s</strong>, please remove or disable the XSS filter in <strong>Configuration</strong> / <strong>Security</strong>."
|
||||
|
||||
|
||||
|
||||
@@ -14,12 +14,7 @@ import request from './utils/request';
|
||||
import './utils/2fa';
|
||||
|
||||
// bootstrap jQuery extensions
|
||||
// import 'bootstrap/js/transition';
|
||||
// import 'bootstrap/js/dist/util';
|
||||
// import 'bootstrap/js/dist/dropdown';
|
||||
// import 'bootstrap/js/dist/collapse';
|
||||
import './utils/bootstrap-transition';
|
||||
import './utils/bootstrap-dropdown';
|
||||
import './utils/bootstrap-collapse';
|
||||
|
||||
// tabs memory
|
||||
|
||||
4
themes/grav/app/utils/bootstrap-collapse.js
vendored
4
themes/grav/app/utils/bootstrap-collapse.js
vendored
@@ -138,7 +138,7 @@ import jQuery from 'jquery';
|
||||
};
|
||||
|
||||
Collapse.prototype.getParent = function() {
|
||||
return $(document).find(this.options.parent)
|
||||
return $(this.options.parent)
|
||||
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
|
||||
.each($.proxy(function(i, element) {
|
||||
var $element = $(element);
|
||||
@@ -161,7 +161,7 @@ import jQuery from 'jquery';
|
||||
var target = $trigger.attr('data-target') ||
|
||||
(href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, ''); // strip for ie7
|
||||
|
||||
return $(document).find(target);
|
||||
return $(target);
|
||||
}
|
||||
|
||||
// COLLAPSE PLUGIN DEFINITION
|
||||
|
||||
163
themes/grav/app/utils/bootstrap-dropdown.js
vendored
163
themes/grav/app/utils/bootstrap-dropdown.js
vendored
@@ -1,163 +0,0 @@
|
||||
import jQuery from 'jquery';
|
||||
|
||||
/* ========================================================================
|
||||
* Bootstrap: dropdown.js v3.4.0
|
||||
* http://getbootstrap.com/javascript/#dropdowns
|
||||
* ========================================================================
|
||||
* Copyright 2011-2016 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* ======================================================================== */
|
||||
|
||||
+(function($) {
|
||||
'use strict';
|
||||
|
||||
// DROPDOWN CLASS DEFINITION
|
||||
// =========================
|
||||
|
||||
var backdrop = '.dropdown-backdrop';
|
||||
var toggle = '[data-toggle="dropdown"]';
|
||||
var Dropdown = function(element) {
|
||||
$(element).on('click.bs.dropdown', this.toggle);
|
||||
};
|
||||
|
||||
Dropdown.VERSION = '3.4.0';
|
||||
|
||||
function getParent($this) {
|
||||
var selector = $this.attr('data-target');
|
||||
|
||||
if (!selector) {
|
||||
selector = $this.attr('href');
|
||||
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); // strip for ie7
|
||||
}
|
||||
|
||||
var $parent = selector && $(document).find(selector);
|
||||
|
||||
return $parent && $parent.length ? $parent : $this.parent();
|
||||
}
|
||||
|
||||
function clearMenus(e) {
|
||||
if (e && e.which === 3) return;
|
||||
$(backdrop).remove();
|
||||
$(toggle).each(function() {
|
||||
var $this = $(this);
|
||||
var $parent = getParent($this);
|
||||
var relatedTarget = { relatedTarget: this };
|
||||
|
||||
if (!$parent.hasClass('open')) return;
|
||||
|
||||
if (e && e.type === 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return;
|
||||
|
||||
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget));
|
||||
|
||||
if (e.isDefaultPrevented()) return;
|
||||
|
||||
$this.attr('aria-expanded', 'false');
|
||||
$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget));
|
||||
});
|
||||
}
|
||||
|
||||
Dropdown.prototype.toggle = function(e) {
|
||||
var $this = $(this);
|
||||
|
||||
if ($this.is('.disabled, :disabled')) return;
|
||||
|
||||
var $parent = getParent($this);
|
||||
var isActive = $parent.hasClass('open');
|
||||
|
||||
clearMenus();
|
||||
|
||||
if (!isActive) {
|
||||
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
|
||||
// if mobile we use a backdrop because click events don't delegate
|
||||
$(document.createElement('div'))
|
||||
.addClass('dropdown-backdrop')
|
||||
.insertAfter($(this))
|
||||
.on('click', clearMenus);
|
||||
}
|
||||
|
||||
var relatedTarget = { relatedTarget: this };
|
||||
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget));
|
||||
|
||||
if (e.isDefaultPrevented()) return;
|
||||
|
||||
$this
|
||||
.trigger('focus')
|
||||
.attr('aria-expanded', 'true');
|
||||
|
||||
$parent
|
||||
.toggleClass('open')
|
||||
.trigger($.Event('shown.bs.dropdown', relatedTarget));
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Dropdown.prototype.keydown = function(e) {
|
||||
if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return;
|
||||
|
||||
var $this = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if ($this.is('.disabled, :disabled')) return;
|
||||
|
||||
var $parent = getParent($this);
|
||||
var isActive = $parent.hasClass('open');
|
||||
|
||||
if (!isActive && e.which !== 27 || isActive && e.which === 27) {
|
||||
if (e.which === 27) $parent.find(toggle).trigger('focus');
|
||||
return $this.trigger('click');
|
||||
}
|
||||
|
||||
var desc = ' li:not(.disabled):visible a';
|
||||
var $items = $parent.find('.dropdown-menu' + desc);
|
||||
|
||||
if (!$items.length) return;
|
||||
|
||||
var index = $items.index(e.target);
|
||||
|
||||
if (e.which === 38 && index > 0) index--; // up
|
||||
if (e.which === 40 && index < $items.length - 1) index++; // down
|
||||
if (!~index) index = 0;
|
||||
|
||||
$items.eq(index).trigger('focus');
|
||||
};
|
||||
|
||||
// DROPDOWN PLUGIN DEFINITION
|
||||
// ==========================
|
||||
|
||||
function Plugin(option) {
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.dropdown');
|
||||
|
||||
if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)));
|
||||
if (typeof option === 'string') data[option].call($this);
|
||||
});
|
||||
}
|
||||
|
||||
var old = $.fn.dropdown;
|
||||
|
||||
$.fn.dropdown = Plugin;
|
||||
$.fn.dropdown.Constructor = Dropdown;
|
||||
|
||||
// DROPDOWN NO CONFLICT
|
||||
// ====================
|
||||
|
||||
$.fn.dropdown.noConflict = function() {
|
||||
$.fn.dropdown = old;
|
||||
return this;
|
||||
};
|
||||
|
||||
// APPLY TO STANDARD DROPDOWN ELEMENTS
|
||||
// ===================================
|
||||
|
||||
$(document)
|
||||
.on('click.bs.dropdown.data-api', clearMenus)
|
||||
.on('click.bs.dropdown.data-api', '.dropdown form', function(e) { e.stopPropagation(); })
|
||||
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
|
||||
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
|
||||
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown);
|
||||
|
||||
}(jQuery));
|
||||
2
themes/grav/css-compiled/preset.css
vendored
2
themes/grav/css-compiled/preset.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -13,7 +13,6 @@
|
||||
"author": "RocketTheme, LLC",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bootstrap": "^4.1.3",
|
||||
"chartist": "0.11.0",
|
||||
"codemirror": "^5.30.0",
|
||||
"cookies-js": "^1.2.3",
|
||||
|
||||
@@ -567,6 +567,16 @@ tr {
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-mobile-open {
|
||||
#admin-main {
|
||||
.lines-button {
|
||||
.lines, .lines:before, .lines:after {
|
||||
background: $logo-link;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#admin-dashboard {
|
||||
|
||||
.admin-block {
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
{% if field.resizer is not defined or field.resizer not in ['off', 'false', 0] %}<div class="grav-editor-resizer"></div>{% endif %}
|
||||
{% if field.description %}
|
||||
<div class="form-extra-wrapper {{ field.size }} {{ field.wrapper_classes }}">
|
||||
<span class="form-description">
|
||||
{% if field.markdown %}
|
||||
{{ field.description|tu|markdown(false)|raw }}
|
||||
{% else %}
|
||||
{{ field.description|tu|raw }}
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="form-description">
|
||||
{% if field.markdown %}
|
||||
{{ field.description|tu|markdown(false)|raw }}
|
||||
{% else %}
|
||||
{{ field.description|tu|raw }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -132,6 +132,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% block titlebar %}
|
||||
|
||||
<div class="button-bar">
|
||||
{% if mode == 'list' %}
|
||||
<a class="button" href="{{ base_url }}"><i class="fa fa-reply"></i> {{ "PLUGIN_ADMIN.BACK"|tu }}</a>
|
||||
@@ -319,6 +320,10 @@
|
||||
|
||||
</div>
|
||||
|
||||
{# Set current form data back into page content #}
|
||||
{% if current_form_data %}
|
||||
{% do context.content(current_form_data.content) %}
|
||||
{% endif %}
|
||||
{% if context.blueprints.fields and admin.session.expert == '0' %}
|
||||
{% include 'partials/blueprints.html.twig' with { blueprints: context.blueprints, data: context } %}
|
||||
{% else %}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user