Security fix and preparation for release 3.3.4 - please update!

This commit is contained in:
Kajetan Dvoracek 2022-02-15 10:03:17 +01:00
parent b9df5c64b1
commit 09872017bb
10 changed files with 142 additions and 299 deletions

View File

@ -692,6 +692,26 @@ class Helper
return self::checkIdentifier($id, 'PPN');
}
/**
* Determine whether or not $url is a valid URL using HTTP or HTTPS scheme.
*
* @param string $url
*
* @return bool
*/
public static function isValidHttpUrl($url)
{
if (!GeneralUtility::isValidUrl($url)) {
return false;
}
$parsed = parse_url($url);
$scheme = $parsed['scheme'] ?? '';
$schemeNormalized = strtolower($scheme);
return $schemeNormalized === 'http' || $schemeNormalized === 'https';
}
/**
* Load value from user's session.
*

View File

@ -12,6 +12,7 @@
namespace Kitodo\Dlf\Plugin\Eid;
use Kitodo\Dlf\Common\Helper;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Http\Response;
@ -26,7 +27,6 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
*/
class PageViewProxy
{
/**
* The main method of the eID script
*
@ -37,29 +37,29 @@ class PageViewProxy
*/
public function main(ServerRequestInterface $request)
{
// header parameter for getUrl(); allowed values 0,1,2; default 0
$header = (int) $request->getQueryParams()['header'];
$header = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($header, 0, 2, 0);
// the URI to fetch data or header from
$url = (string) $request->getQueryParams()['url'];
if (!GeneralUtility::isValidUrl($url)) {
if (!Helper::isValidHttpUrl($url)) {
throw new \InvalidArgumentException('No valid url passed!', 1580482805);
}
// fetch the requested data or header
$fetchedData = GeneralUtility::getUrl($url, $header);
// get and verify the uHash
$uHash = (string) $request->getQueryParams()['uHash'];
if (!hash_equals(GeneralUtility::hmac($url, 'PageViewProxy'), $uHash)) {
throw new \InvalidArgumentException('No valid uHash passed!', 1643796565);
}
// fetch the requested data
$fetchedData = GeneralUtility::getUrl($url);
// Fetch header data separately to get "Last-Modified" info
if ($header === 0) {
$fetchedHeaderString = GeneralUtility::getUrl($url, 2);
if (!empty($fetchedHeaderString)) {
$fetchedHeader = explode("\n", $fetchedHeaderString);
foreach ($fetchedHeader as $headerline) {
if (stripos($headerline, 'Last-Modified:') !== false) {
$lastModified = trim(substr($headerline, strpos($headerline, ':') + 1));
break;
}
$fetchedHeaderString = GeneralUtility::getUrl($url, 2);
if (!empty($fetchedHeaderString)) {
$fetchedHeader = explode("\n", $fetchedHeaderString);
foreach ($fetchedHeader as $headerline) {
if (stripos($headerline, 'Last-Modified:') !== false) {
$lastModified = trim(substr($headerline, strpos($headerline, ':') + 1));
break;
}
}
}
@ -74,9 +74,9 @@ class PageViewProxy
$response = $response->withHeader('Access-Control-Max-Age', '86400');
$response = $response->withHeader('Content-Type', finfo_buffer(finfo_open(FILEINFO_MIME), $fetchedData));
}
if ($header === 0 && !empty($lastModified)) {
if (!empty($lastModified)) {
$response = $response->withHeader('Last-Modified', $lastModified);
}
return $response;
}
}
}

View File

@ -191,7 +191,7 @@ class PageView extends \Kitodo\Dlf\Common\AbstractPlugin
'parameter' => $GLOBALS['TSFE']->id,
'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'],
'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($image['url']),
'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($image['url']) . '&uHash=' . GeneralUtility::hmac($image['url'], 'PageViewProxy'),
];
$image['url'] = $this->cObj->typoLink_URL($linkConf);
}
@ -230,7 +230,7 @@ class PageView extends \Kitodo\Dlf\Common\AbstractPlugin
'parameter' => $GLOBALS['TSFE']->id,
'forceAbsoluteUrl' => !empty($this->conf['forceAbsoluteUrl']) ? 1 : 0,
'forceAbsoluteUrl.' => ['scheme' => !empty($this->conf['forceAbsoluteUrl']) && !empty($this->conf['forceAbsoluteUrlHttps']) ? 'https' : 'http'],
'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($fulltext['url']),
'additionalParams' => '&eID=tx_dlf_pageview_proxy&url=' . urlencode($fulltext['url']) . '&uHash=' . GeneralUtility::hmac($fulltext['url'], 'PageViewProxy'),
];
$fulltext['url'] = $this->cObj->typoLink_URL($linkConf);
}

View File

@ -175,6 +175,7 @@
<label index="tt_content.dlf_toolbox">DLF: Toolbox</label>
<label index="tt_content.dlf_validator">DLF: Validator</label>
<label index="config.metadataFormats">Default metadata namespaces</label>
<label index="config.enableInternalProxy">Enable internal page view proxy?: (default is "FALSE")</label>
<label index="config.useragent">DLF User-Agent: (default is "Kitodo.Presentation")</label>
<label index="config.forceAbsoluteUrl">Force all links to pages and resources to be absolute?: Only needed for some multi-domain environments; requires a fully qualified Entry Point in Site Configuration (default is "FALSE")</label>
<label index="config.forceAbsoluteUrlHttps">Use HTTPS for absolute links?: requires a valid Entry Point with "https://..." in Site Configuration (default is "FALSE")</label>
@ -385,6 +386,7 @@
<label index="tt_content.dlf_toolbox">DLF: Werkzeugkasten</label>
<label index="tt_content.dlf_validator">DLF: Validator</label>
<label index="config.metadataFormats">Standard-Namensräume für Metadaten</label>
<label index="config.enableInternalProxy">Internen Proxy für Werkansicht aktivieren? (Standard ist "FALSE")</label>
<label index="config.useragent">DLF User-Agent: (Standard ist "Kitodo.Presentation")</label>
<label index="config.forceAbsoluteUrl">Verwende nur absolute Links für Seiten und Ressourcen?: Wird nur in speziellen Multi-Domain-Umgebungen benötigt; erfordert einen voll qualifizierten Einstiegspunkt in der Seitenkonfiguration (Standard ist "FALSE")</label>
<label index="config.forceAbsoluteUrlHttps">Verwende HTTPS for absolute Links?: erfordert einen Einstiegspunkt mit "https://..." in der Seitenkonfiguration (Standard ist "FALSE")</label>

View File

@ -9,17 +9,9 @@
*/
/**
* Right know the image manipulation uses an own ol.Map object based on a webgl renderer. This is due to the fact
* that other parts of the viewer application are using vector geometries and ol3 does only support full vector
* renderering with the canvas and dom renderer yet. In contrast the image manipulation tool is only working
* with a webgl renderer. Therefore it uses an own ol.Map object which is overlaid and synchronized with the
* base ol.Map object.
*
* @constructor
* @param {Object=} options Control options.
* {Array.<ol.layer.Layer>} layers
* {Element} target
* {ol.View} view
* {ol.Map} map
*/
dlfViewerImageManipulationControl = function(options) {
@ -32,30 +24,12 @@ dlfViewerImageManipulationControl = function(options) {
dlfUtils.parseDataDic($('#tx-dlf-tools-imagetools')) :
{'imagemanipulation-on':'Activate image manipulation', 'imagemanipulation-off':'Deactivate image manipulation', 'saturation':'Saturation', 'hue':'Hue', 'brightness':'Brightness', 'contrast':'Contrast', 'reset':'Reset', 'invert':'Color inverting', 'parentContainer':'.tx-dlf-imagemanipulationtool'};
/**
* @type {Array.<ol.layer.Layer>}
* @private
*/
this.layers = options.layers;
/**
* @type {ol.Map}
* @private
*/
this.baseMap_ = options.map;
/**
* @type {ol.Map|undefined}
* @private
*/
this.map_ = undefined;
/**
* @type {ol.View}
* @private
*/
this.view_ = options.view;
/**
* @type {Element}
* @private
@ -73,6 +47,12 @@ dlfViewerImageManipulationControl = function(options) {
*/
this.toolContainerEl_ = dlfUtils.exists(options.toolContainer) ? options.toolContainer : $(this.dic['parentContainer'])[0];
/**
* @type {HTMLCanvasElement}
*
*/
this.canvas_ = this.baseMap_.getTargetElement().querySelector('canvas');
//
// Append open/close behavior to toolbox
//
@ -95,8 +75,8 @@ dlfViewerImageManipulationControl = function(options) {
var FILTERS_DEFAULT_ = {
'brightness': 1,
'contrast': 1,
'hue': 0,
'saturation': 0
'hue-rotate': 0,
'saturate': 0
};
/**
@ -105,47 +85,14 @@ dlfViewerImageManipulationControl = function(options) {
*/
this.filters_ = $.extend({}, FILTERS_DEFAULT_);
/**
* Is filter updated
* @type {boolean}
* @private
*/
this.filterUpdated_ = false;
/**
* @type {Object}
* @private
*/
this.handler_ = {
'postcomposeImageFilter': $.proxy(function (event) {
var webglContext = event['glContext'],
canvas = $('#' + this.map_.getTargetElement().id + ' canvas.ol-unselectable')[0];
if (webglContext !== undefined && webglContext !== null) {
var gl = webglContext.getGL();
if (this.filterUpdated_) {
glif.reset();
for (var filter in this.filters_) {
glif.addFilter(filter, this.filters_[String(filter)]);
}
this.filterUpdated_ = false;
}
glif.apply(gl, canvas);
// for showing openlayers that the program changed
// if missing openlayers will produce errors because it
// expected other shaders in the webgl program
webglContext.useProgram(undefined);
}
}, this),
'resetFilter': $.proxy(function(event) {
'resetFilter': $.proxy(function() {
// reset the checked filters
if (this.filters_.hasOwnProperty('invert')) {
if (this.filters_['invert']) {
$('#invert-filter').click();
}
@ -162,30 +109,47 @@ dlfViewerImageManipulationControl = function(options) {
};
};
/**
* Set filter style property on map canvas.
*
* @param {string} filters
*/
dlfViewerImageManipulationControl.prototype.setCssFilter_ = function (filters) {
this.canvas_.style.filter = filters;
this.canvas_.style.webkitFilter = filters;
}
/**
* @private
*/
dlfViewerImageManipulationControl.prototype.applyFilters_ = function () {
var filters = '';
for (var filter in this.filters_) {
if (!this.filters_.hasOwnProperty(filter)) {
continue;
}
var cssValue = this.valueToCss_(filter, this.filters_[filter]);
if (cssValue === undefined) {
continue;
}
filters += filter + '(' + cssValue + ') ';
}
this.setCssFilter_(filters);
}
/**
* Activates the image manipulation tool
*/
dlfViewerImageManipulationControl.prototype.activate = function(){
// Apply filters from last time
this.applyFilters_();
//
// Toggle maps
//
$.when($(this.baseMap_.getTargetElement())
// fadeOut the base map container
.hide())
// fadeIn image map container
.done($.proxy(function(){
if (!dlfUtils.exists(this.map_)) {
// create map container and map object if not exists yet
this.createMap_();
}
// Show map
$(this.map_.getTargetElement()).show();
// trigger open event
$(this).trigger("activate-imagemanipulation", this.map_);
}, this));
$(this).trigger("activate-imagemanipulation", this.baseMap_);
//
// Toggle toolbox controls
@ -199,10 +163,6 @@ dlfViewerImageManipulationControl.prototype.activate = function(){
this.createFilters_();
}
$(this.sliderContainer_).show().addClass('open');
// add postcompose listener to layers
if (this.map_ !== undefined)
this.map_.on('postcompose', this.handler_.postcomposeImageFilter);
};
/**
@ -230,7 +190,7 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() {
[1, 0, 2, 0.01], this.dic['contrast'], function(v) {
return parseInt(v * 100 - 100);
}),
saturationSlider = this.createSlider_('slider-saturation', 'horizontal', 'saturation',
saturationSlider = this.createSlider_('slider-saturation', 'horizontal', 'saturate',
[0, -1, 1, 0.01], this.dic['saturation'], function(v) {
return parseInt(v * 100);
}),
@ -238,7 +198,7 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() {
[1, 0, 2, 0.1], this.dic['brightness'],function(v) {
return parseInt(v * 100 - 100);
}),
hueSlider = this.createSlider_('slider-hue', 'horizontal', 'hue',
hueSlider = this.createSlider_('slider-hue', 'horizontal', 'hue-rotate',
[0, -180, 180, 5], this.dic['hue'], function(v) {
return parseInt(v);
});
@ -252,19 +212,10 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() {
$(this.sliderContainer_).append($('<div class="checkbox"><label><input type="checkbox" id="' + elFilterId + '">' +
this.dic['invert'] + '</label></div>'));
$('#' + elFilterId).on('click', $.proxy(function(event) {
if (event.target.checked === true && !this.filters_.hasOwnProperty('invert')) {
// if checked add the invert filter to the filters
this.filters_['invert'] = true;
} else {
// remove invert filter
if (this.filters_.hasOwnProperty('invert')) {
delete this.filters_['invert'];
}
}
var invert = event.target.checked;
// update filter chain
this.filterUpdated_ = true;
this.layers[0].changed();
this.setFilter_('invert', invert);
}, this));
// button for reset to default state
@ -273,72 +224,6 @@ dlfViewerImageManipulationControl.prototype.createFilters_ = function() {
$(resetBtn).on('click', this.handler_.resetFilter);
};
/**
* Setup the map object used from the image manipulation tool and bind it to the baseMap
* @private
*/
dlfViewerImageManipulationControl.prototype.createMap_ = function() {
var mapEl_ = $('<div id="tx-dlf-map-manipulate" class="tx-dlf-map"></div>');
$(this.baseMap_.getTargetElement().parentElement).append(mapEl_);
this.map_ = new ol.Map({
layers: this.layers,
target: mapEl_[0].id,
controls: [],
interactions: [
new ol.interaction.DragRotate(),
new ol.interaction.DragPan(),
new ol.interaction.DragZoom(),
new ol.interaction.PinchRotate(),
new ol.interaction.PinchZoom(),
new ol.interaction.MouseWheelZoom(),
new ol.interaction.KeyboardPan(),
new ol.interaction.KeyboardZoom(),
new ol.interaction.DragRotateAndZoom()
],
// necessary for proper working of the keyboard events
keyboardEventTarget: document,
view: this.view_,
renderer: 'webgl'
});
// couple map behavior with baseMap
var adjustViews = function(sourceView, destMap) {
var rotateDiff = sourceView.getRotation() !== destMap.getView().getRotation();
var resDiff = sourceView.getResolution() !== destMap.getView().getResolution();
var centerDiff = sourceView.getCenter() !== destMap.getView().getCenter();
if (rotateDiff || resDiff || centerDiff) {
destMap.zoomTo(sourceView.getCenter(),sourceView.getZoom(), 50);
destMap.getView().rotate(sourceView.getRotation());
}
},
adjustViewHandler = function(event) {
adjustViews(event.target, this);
};
// when deactivate / activate adjust both map centers / zoom
$(this).on("activate-imagemanipulation", $.proxy(function(event, map) {
// pass change events for resolution and rotation to image manipulation map
// created through external view controls
this.baseMap_.getView().on('change:resolution', adjustViewHandler, this.map_);
this.baseMap_.getView().on('change:rotation', adjustViewHandler, this.map_);
// adjust the view of both maps
adjustViews(this.baseMap_.getView(), this.map_);
}, this));
$(this).on("deactivate-imagemanipulation", $.proxy(function(event, map) {
// pass change events for resolution and rotation to image manipulation map
// created through external view controls
this.baseMap_.getView().un('change:resolution', adjustViewHandler, this.map_);
this.baseMap_.getView().un('change:rotation', adjustViewHandler, this.map_);
// adjust the view of both maps
adjustViews(this.map_.getView(), this.baseMap_);
}, this));
};
/**
* Functions creates a slider + behavior.
*
@ -366,7 +251,6 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className,
*/
var update = $.proxy(function(event, ui){
var value = ui['value'],
layer = this.layers[0],
element = valueEl[0],
labelValue = dlfUtils.exists(opt_labelFn) ? opt_labelFn(value) : value + '%';
@ -382,9 +266,7 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className,
element.innerHTML = labelValue;
// update filters.
this.filters_[key] = value;
this.filterUpdated_ = true;
layer.changed();
this.setFilter_(key, value);
}, this);
$(sliderEl).slider({
@ -410,12 +292,7 @@ dlfViewerImageManipulationControl.prototype.createSlider_ = function(className,
* Deactivates the image manipulation control
*/
dlfViewerImageManipulationControl.prototype.deactivate = function(){
// toggle maps
if (dlfUtils.exists(this.map_)) {
$(this.map_.getTargetElement()).hide();
}
$(this.baseMap_.getTargetElement()).show();
this.setCssFilter_("");
// toggle view of image manipulation control element
$(this.anchor_).removeClass('active')
@ -424,10 +301,6 @@ dlfViewerImageManipulationControl.prototype.deactivate = function(){
$(this.sliderContainer_).hide().removeClass('open');
// remove postcompose listener to map
if (this.map_ !== undefined)
this.map_.un('postcompose', this.handler_.postcomposeImageFilter);
// trigger close event for trigger map adjust behavior
$(this).trigger("deactivate-imagemanipulation");
};
@ -440,3 +313,39 @@ dlfViewerImageManipulationControl.prototype.deactivate = function(){
dlfViewerImageManipulationControl.prototype.isActive = function() {
return $(this.anchor_).hasClass('active');
};
/**
* @param {string} filter The filter to set
* @param {string} value The value to set the filter to
* @private
*/
dlfViewerImageManipulationControl.prototype.setFilter_ = function (filter, value) {
this.filters_[filter] = value;
this.applyFilters_();
}
/**
* Convert filter value to its CSS representation.
*
* @param {string} filter
* @param {number} value
* @private
* @return {string}
*/
dlfViewerImageManipulationControl.prototype.valueToCss_ = function (filter, value) {
switch (filter) {
case 'contrast':
case 'brightness':
return (value * 100).toString() + '%';
case 'saturate':
return ((value + 1) * 100).toString() + '%';
case 'hue-rotate':
return value + 'deg';
case 'invert':
return value ? '100%' : '0%';
}
}

View File

@ -187,18 +187,12 @@ dlfViewer.prototype.addCustomControls = function() {
//
// Add image manipulation tool if container is added.
//
// It is important to know that the image manipulation tool uses a webgl renderer as basis. Therefor the
// application has as first to check if the renderer is active. Further it has to check if cors supported through
// image.
//
if ($('#tx-dlf-tools-imagetools').length > 0 && dlfUtils.isWebGLEnabled() && this.isCorsEnabled) {
if ($('#tx-dlf-tools-imagetools').length > 0) {
// should be called if cors is enabled
imageManipulationControl = new dlfViewerImageManipulationControl({
controlTarget: $('.tx-dlf-tools-imagetools')[0],
layers: dlfUtils.createOl3Layers(images, '*'),
map: this.map,
view: dlfUtils.createOl3View(images)
});
// bind behavior of both together
@ -214,11 +208,6 @@ dlfViewer.prototype.addCustomControls = function() {
// set on object scope
this.imageManipulationControl = imageManipulationControl;
} else if ($('#tx-dlf-tools-imagetools').length > 0) {
// hide the element because the functionality is not supported through missing webgl or cors support.
$('#tx-dlf-tools-imagetools').addClass('deactivate');
}
};
@ -371,17 +360,7 @@ dlfViewer.prototype.init = function(controlNames) {
if (this.imageUrls.length <= 0)
throw new Error('Missing image source objects.');
/**
* Is cors enabled. Important information for correct renderer and layer initialization
* @type {boolean}
*/
if (this.useInternalProxy) {
this.isCorsEnabled = true;
} else {
this.isCorsEnabled = dlfUtils.isCorsEnabled(this.imageUrls);
}
this.initLayer(this.imageUrls, this.isCorsEnabled)
this.initLayer(this.imageUrls)
.done($.proxy(function(layers){
var controls = controlNames.length > 0 || controlNames[0] === ""
@ -469,11 +448,10 @@ dlfViewer.prototype.init = function(controlNames) {
* Function generate the ol3 layer objects for given image sources. Returns a promise.
*
* @param {Array.<{url: *, mimetype: *}>} imageSourceObjs
* @param {boolean} isCorsEnabled
* @return {jQuery.Deferred.<function(Array.<ol.layer.Layer>)>}
* @private
*/
dlfViewer.prototype.initLayer = function(imageSourceObjs, isCorsEnabled) {
dlfViewer.prototype.initLayer = function(imageSourceObjs) {
// use deferred for async behavior
var deferredResponse = new $.Deferred(),
@ -484,12 +462,11 @@ dlfViewer.prototype.initLayer = function(imageSourceObjs, isCorsEnabled) {
resolveCallback = $.proxy(function(imageSourceData, layers) {
this.images = imageSourceData;
deferredResponse.resolve(layers);
}, this),
origin = isCorsEnabled ? '*' : undefined;
}, this);
dlfUtils.fetchImageData(imageSourceObjs)
.done(function(imageSourceData) {
resolveCallback(imageSourceData, dlfUtils.createOl3Layers(imageSourceData, origin));
resolveCallback(imageSourceData, dlfUtils.createOl3Layers(imageSourceData));
});
return deferredResponse;

View File

@ -716,45 +716,6 @@ dlfUtils.isNullEmptyUndefinedOrNoNumber = function (val) {
return val === null || val === undefined || val === '' || isNaN(val);
};
/**
* @param {Array.<{url: *, mimetype: *}>} imageObjs
* @return {boolean}
*/
dlfUtils.isCorsEnabled = function (imageObjs) {
// fix for proper working with ie
if (!window.location.origin) {
window.location.origin = window.location.protocol + '//' + window.location.hostname +
(window.location.port ? ':' + window.location.port : '');
}
// fetch data from server
// with access control allowed
var response = true;
imageObjs.forEach(function (imageObj) {
var url = imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.ZOOMIFY
? imageObj.url.replace('ImageProperties.xml', 'TileGroup0/0-0-0.jpg')
:
imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.IIIF
? dlfViewerSource.IIIF.getMetdadataURL(imageObj.url)
: imageObj.mimetype === dlfUtils.CUSTOM_MIMETYPE.IIP
? dlfViewerSource.IIP.getMetdadataURL(imageObj.url)
: imageObj.url;
url = window.location.origin + window.location.pathname + '?eID=tx_dlf_pageview_proxy&url=' + encodeURIComponent(url) + '&header=2';
$.ajax({
url: url,
async: false
}).done(function (data, type) {
response = type === 'success' && data.indexOf('Access-Control-Allow-Origin') !== -1;
}).fail(function (data, type) {
response = false;
});
});
return response;
};
/**
* Checks if {@link obj} is a valid object describing the location of a
* fulltext (@see PageView::getFulltext in PageView.php).
@ -771,36 +732,6 @@ dlfUtils.isFulltextDescriptor = function (obj) {
);
};
/**
* Functions checks if WebGL is enabled in the browser
* @return {boolean}
*/
dlfUtils.isWebGLEnabled = function () {
if (!!window.WebGLRenderingContext) {
var canvas = document.createElement("canvas"),
rendererNames = ["webgl", "experimental-webgl", "moz-webgl", "webkit-3d"],
context = false;
for (var i = 0; i < rendererNames.length; i++) {
try {
context = canvas.getContext(rendererNames[i]);
if (context && typeof context.getParameter === "function") {
// WebGL is enabled;
return true;
}
} catch (e) {
/* eslint no-console: ["error", { allow: ["info"] }] */
console.info(e);
}
}
// WebGL not supported
return false;
}
// WebGL not supported
return false;
};
/**
* @param {Element} element
* @return {Object}

View File

@ -1,5 +1,7 @@
# cat=Basic; type=user[Kitodo\Dlf\Hooks\ConfigurationForm->checkMetadataFormats]; label=LLL:EXT:dlf/Resources/Private/Language/Labels.xml:config.metadataFormats
metadataFormats = 0
# cat=Basic; type=boolean; label=LLL:EXT:dlf/Resources/Private/Language/Labels.xml:config.enableInternalProxy
enableInternalProxy = 0
# cat=Basic; type=string; label=LLL:EXT:dlf/Resources/Private/Language/Labels.xml:config.useragent
useragent = Kitodo.Presentation
# cat=Basic; type=boolean; label=LLL:EXT:dlf/Resources/Private/Language/Labels.xml:config.forceAbsoluteUrl

View File

@ -13,7 +13,7 @@
$EM_CONF[$_EXTKEY] = [
'title' => 'Kitodo.Presentation',
'description' => 'Base plugins, modules, services and API of the Digital Library Framework. It is part of the community-based Kitodo Digitization Suite.',
'version' => '3.3.3',
'version' => '3.3.4',
'category' => 'misc',
'constraints' => [
'depends' => [

View File

@ -220,7 +220,9 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['dlf/Classes/Common/MetsDocument.php']
// Register AJAX eID handlers.
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_search_suggest'] = \Kitodo\Dlf\Plugin\Eid\SearchSuggest::class . '::main';
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_search_in_document'] = \Kitodo\Dlf\Plugin\Eid\SearchInDocument::class . '::main';
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_pageview_proxy'] = \Kitodo\Dlf\Plugin\Eid\PageViewProxy::class . '::main';
if ($GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['dlf']['enableInternalProxy'] ?? false) {
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['tx_dlf_pageview_proxy'] = \Kitodo\Dlf\Plugin\Eid\PageViewProxy::class . '::main';
}
// Use Caching Framework for Solr queries
if (!is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['tx_dlf_solr'])) {
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['tx_dlf_solr'] = [];