Jforrester has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/340330 )
Change subject: Fix security/general concerns ...................................................................... Fix security/general concerns I skipped two concerns, namely * "threed" as being confused with "thread" is probably not worth fixing now * three.js is unwieldy, but I'm not sure there's a "good" way to fix that Bug: T157077 Change-Id: Ifc716148ae40e87c8e9d5b650e069dee9e09d43d --- M ThreeDHandler.php D ThreeDHooks.php M extension.json M i18n/en.json M i18n/qqq.json M modules/mmv.3d.js D modules/three/AMFLoader.js D tests/3d.test.js D tests/3d.test.php 9 files changed, 32 insertions(+), 579 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/3D refs/changes/30/340330/1 diff --git a/ThreeDHandler.php b/ThreeDHandler.php index 7676111..4b10c84 100644 --- a/ThreeDHandler.php +++ b/ThreeDHandler.php @@ -41,7 +41,7 @@ return false; } - # Don't make an image bigger than wgMaxSVGSize on the smaller side + // Don't make an image bigger than wgMaxSVGSize on the smaller side if ( $params['physicalWidth'] <= $params['physicalHeight'] ) { if ( $params['physicalWidth'] > $wgSVGMaxSize ) { $srcWidth = $image->getWidth(); @@ -70,7 +70,7 @@ * @return MediaTransformError|MediaTransformOutput|ThumbnailImage|TransformParameterError */ function doTransform( $image, $dstPath, $dstUrl, $params, $flags = 0 ) { - global $wg3dProcessor, $wg3dProcessEnviron; + global $wg3dProcessor, $wg3dProcessEnviron, $wgMaxShellMemory; // Impose an aspect ratio $params['height'] = round( $params['width'] / ( 640 / 480 ) ); @@ -79,12 +79,12 @@ return new ThumbnailImage( $image, $dstUrl, $dstPath, $params ); } + $width = $params['width']; + $height = $params['height']; + if ( !wfMkdirParents( dirname( $dstPath ), null, __METHOD__ ) ) { return $this->doThumbError( $width, $height, 'thumbnail_dest_directory' ); } - - $width = $params['width']; - $height = $params['height']; $srcPath = $image->getLocalRefPath(); @@ -101,7 +101,7 @@ $err = wfShellExecWithStderr( $cmd, $retval, $wg3dProcessEnviron, [ 'memory' => '10000000' ] ); wfProfileOut( 'ThreeDHandler' ); - if ( $retval != 0 || $removed ) { + if ( $retval != 0 ) { wfDebugLog( 'thumbnail', sprintf( 'thumbnail failed on %s: error %d "%s" from "%s"', wfHostname(), $retval, trim( $err ), $cmd ) ); diff --git a/ThreeDHooks.php b/ThreeDHooks.php deleted file mode 100644 index c0dc520..0000000 --- a/ThreeDHooks.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php -/** - * 3d extension hooks - * - * @file - * @ingroup Extensions - * @license MIT - */ -class ThreeDHooks { - - public static function onResourceLoaderTestModules( - array &$testModules, - ResourceLoader &$resourceLoader - ) { - - } - -} diff --git a/extension.json b/extension.json index b9ff0a1..b2e04ef 100644 --- a/extension.json +++ b/extension.json @@ -15,11 +15,6 @@ "i18n" ] }, - "Hooks": { - "ResourceLoaderTestModules": [ - "ThreeDHooks::onResourceLoaderTestModules" - ] - }, "ResourceModules": { "ext.3d": { "scripts": [ @@ -35,7 +30,6 @@ "scripts": [ "mmv.3d.js", "three/three.js", - "three/AMFLoader.js", "three/STLLoader.js", "three/OrbitControls.js" ], @@ -52,11 +46,10 @@ "remoteExtPath": "3d/modules" }, "AutoloadClasses": { - "ThreeDHooks": "ThreeDHooks.php", "ThreeDHandler": "ThreeDHandler.php" }, "MediaHandlers": { "application/x-amf": "ThreeDHandler", "application/sla": "ThreeDHandler" } -} \ No newline at end of file +} diff --git a/i18n/en.json b/i18n/en.json index 291e8db..9ae453e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -1,9 +1,9 @@ { - "@metadata": { - "authors": [ - "Gilles Dubuc" - ] - }, - "3d": "3d", - "3d-desc": "Provides support for 3d file formats." -} \ No newline at end of file + "@metadata": { + "authors": [ + "Gilles Dubuc" + ] + }, + "3d": "3d", + "3d-desc": "Provides support for 3d file formats." +} diff --git a/i18n/qqq.json b/i18n/qqq.json index 8880d4b..89dbb4c 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -1,9 +1,9 @@ { - "@metadata": { - "authors": [ - "Gilles Dubuc" - ] - }, - "3d": "The name of the extension", - "3d-desc": "{{desc|name=3d|url=https://www.mediawiki.org/wiki/Extension:3d}}" -} \ No newline at end of file + "@metadata": { + "authors": [ + "Gilles Dubuc" + ] + }, + "3d": "The name of the extension", + "3d-desc": "{{desc|name=3d|url=https://www.mediawiki.org/wiki/Extension:3d}}" +} diff --git a/modules/mmv.3d.js b/modules/mmv.3d.js index b1e8bf7..a166604 100644 --- a/modules/mmv.3d.js +++ b/modules/mmv.3d.js @@ -1,18 +1,18 @@ /* - * This file is part of the MediaWiki extension MultimediaViewer. + * This file is part of the MediaWiki extension 3D. * - * MultimediaViewer is free software: you can redistribute it and/or modify + * The 3D extension is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * - * MultimediaViewer is distributed in the hope that it will be useful, + * The 3D extension 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 General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with MultimediaViewer. If not, see <http://www.gnu.org/licenses/>. + * along with The 3D extension. If not, see <http://www.gnu.org/licenses/>. */ ( function ( mw, $ ) { @@ -59,9 +59,9 @@ TD.center = function ( object ) { var bbox, bboxWidth, bboxHeight, bboxDepth, camerax, cameray, cameraz; - if ( object.type == 'Group' ) { + if ( object.type === 'Group' ) { this.center( object.children[ 0 ] ); - } else if ( object.type == 'Mesh' ) { + } else if ( object.type === 'Mesh' ) { object.geometry.center(); object.geometry.computeBoundingBox(); @@ -89,16 +89,14 @@ request, loader; - if ( extension == 'stl' ) { + if ( extension === 'stl' ) { loader = new THREE.STLLoader( this.manager ); - } else if ( extension == 'amf' ) { - loader = new THREE.AMFLoader( this.manager ); } request = loader.load( url, function ( data ) { var object = data; - if ( extension == 'stl' ) { + if ( extension === 'stl' ) { object = threed.geometryToObject( data ); } @@ -195,7 +193,7 @@ var extension = e.image.filePageTitle.ext; // Ignore events from formats that we don't care about - if ( $.inArray( extension, [ 'amf', 'stl' ] ) == -1 ) { + if ( $.inArray( extension, [ 'amf', 'stl' ] ) === -1 ) { return; } diff --git a/modules/three/AMFLoader.js b/modules/three/AMFLoader.js deleted file mode 100644 index ade823c..0000000 --- a/modules/three/AMFLoader.js +++ /dev/null @@ -1,501 +0,0 @@ -/* - * @author tamarintech / https://tamarintech.com - * - * Description: Early release of an AMF Loader following the pattern of the - * example loaders in the three.js project. - * - * More information about the AMF format: http://amf.wikispaces.com - * - * Usage: - * var loader = new AMFLoader(); - * loader.load('/path/to/project.amf', function(objecttree) { - * scene.add(objecttree); - * }); - * - * Materials now supported, material colors supported - * Zip support, requires jszip - * TextDecoder polyfill required by some browsers (particularly IE, Edge) - * No constellation support (yet)! - * - */ - -THREE.AMFLoader = function ( manager ) { - - this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; - -}; - -THREE.AMFLoader.prototype = { - - constructor: THREE.AMFLoader, - - load: function ( url, onLoad, onProgress, onError ) { - - var scope = this; - - var loader = new THREE.XHRLoader( scope.manager ); - loader.setResponseType( 'arraybuffer' ); - return loader.load( url, function( text ) { - - onLoad( scope.parse( text ) ); - - }, onProgress, onError ); - - }, - - parse: function ( data ) { - - function loadDocument( data ) { - - var view = new DataView( data ); - var magic = String.fromCharCode( view.getUint8( 0 ), view.getUint8( 1 ) ); - - if ( magic === "PK" ) { - - var zip = null; - var file = null; - - console.log( "Loading Zip" ); - - try { - - zip = new JSZip( data ); - - } catch ( e ) { - - if ( e instanceof ReferenceError ) { - - console.log( " jszip missing and file is compressed." ); - return null; - - } - - } - - for ( file in zip.files ) { - - if ( file.toLowerCase().substr( - 4 ) === '.amf' ) { - - break; - - } - - } - - console.log( " Trying to load file asset: " + file ); - view = new DataView( zip.file( file ).asArrayBuffer() ); - - } - - if ( TextDecoder === undefined ) { - - console.log( " TextDecoder not present. Please use TextDecoder polyfill." ); - return null; - - } - - var fileText = new TextDecoder( 'utf-8' ).decode( view ); - var xmlData = new DOMParser().parseFromString( fileText, 'application/xml' ); - - if ( xmlData.documentElement.nodeName.toLowerCase() !== "amf" ) { - - console.log( " Error loading AMF - no AMF document found." ); - return null; - - } - - return xmlData; - - } - - function loadDocumentScale( node ) { - - var scale = 1.0; - var unit = 'millimeter'; - - if ( node.documentElement.attributes[ 'unit' ] !== undefined ) { - - unit = node.documentElement.attributes[ 'unit' ].value.toLowerCase(); - - } - - var scaleUnits = { - 'millimeter': 1.0, - 'inch': 25.4, - 'feet': 304.8, - 'meter': 1000.0, - 'micron': 0.001 - }; - - if ( scaleUnits[ unit ] !== undefined ) { - - scale = scaleUnits[ unit ]; - - } - - console.log( " Unit scale: " + scale ); - return scale; - - } - - function loadMaterials( node ) { - - var matName = "AMF Material"; - var matId = node.attributes[ 'id' ].textContent; - var color = { r: 1.0, g: 1.0, b: 1.0, a: 1.0 }; - - var loadedMaterial = null; - - for ( var i = 0; i < node.children.length; i ++ ) { - - var matChildEl = node.children[ i ]; - - if ( matChildEl.nodeName === "metadata" && matChildEl.attributes[ 'type' ] !== undefined ) { - - if ( matChildEl.attributes[ 'type' ].value === 'name' ) { - - matname = matChildEl.textContent; - - } - - } else if ( matChildEl.nodeName === 'color' ) { - - color = loadColor( matChildEl ); - - } - - } - - loadedMaterial = new THREE.MeshPhongMaterial( { - shading: THREE.FlatShading, - color: new THREE.Color( color.r, color.g, color.b ), - name: matName - } ); - - if ( color.a !== 1.0 ) { - - loadedMaterial.transparent = true; - loadedMaterial.opacity = color.a; - - } - - return { 'id': matId, 'material': loadedMaterial }; - - } - - function loadColor( node ) { - - var color = { 'r': 1.0, 'g': 1.0, 'b': 1.0, 'a': 1.0 }; - - for ( var i = 0; i < node.children.length; i ++ ) { - - var matColor = node.children[ i ]; - - if ( matColor.nodeName === 'r' ) { - - color.r = matColor.textContent; - - } else if ( matColor.nodeName === 'g' ) { - - color.g = matColor.textContent; - - } else if ( matColor.nodeName === 'b' ) { - - color.b = matColor.textContent; - - } else if ( matColor.nodeName === 'a' ) { - - color.a = matColor.textContent; - - } - - } - - return color; - - } - - function loadMeshVolume( node ) { - - var volume = { "name": "", "triangles": [], "materialid": null }; - - var currVolumeNode = node.firstElementChild; - - if ( node.attributes[ 'materialid' ] !== undefined ) { - - volume.materialId = node.attributes[ 'materialid' ].nodeValue; - - } - - while ( currVolumeNode ) { - - if ( currVolumeNode.nodeName === "metadata" ) { - - if ( currVolumeNode.attributes[ 'type' ] !== undefined ) { - - if ( currVolumeNode.attributes[ 'type' ].value === 'name' ) { - - volume.name = currVolumeNode.textContent; - - } - - } - - } else if ( currVolumeNode.nodeName === "triangle" ) { - - var v1 = currVolumeNode.getElementsByTagName("v1")[0].textContent; - var v2 = currVolumeNode.getElementsByTagName("v2")[0].textContent; - var v3 = currVolumeNode.getElementsByTagName("v3")[0].textContent; - - volume.triangles.push( v1 ); - volume.triangles.push( v2 ); - volume.triangles.push( v3 ); - - } - - currVolumeNode = currVolumeNode.nextElementSibling; - - } - - return volume; - - } - - function loadMeshVertices( node ) { - - var vertArray = []; - var normalArray = []; - var currVerticesNode = node.firstElementChild; - - while ( currVerticesNode ) { - - if ( currVerticesNode.nodeName === "vertex" ) { - - var vNode = currVerticesNode.firstElementChild; - - while ( vNode ) { - - if ( vNode.nodeName === "coordinates" ) { - - var x = vNode.getElementsByTagName("x")[0].textContent; - var y = vNode.getElementsByTagName("y")[0].textContent; - var z = vNode.getElementsByTagName("z")[0].textContent; - - vertArray.push(x); - vertArray.push(y); - vertArray.push(z); - - } else if ( vNode.nodeName === "normal" ) { - - var nx = vNode.getElementsByTagName("nx")[0].textContent; - var ny = vNode.getElementsByTagName("ny")[0].textContent; - var nz = vNode.getElementsByTagName("nz")[0].textContent; - - normalArray.push(nx); - normalArray.push(ny); - normalArray.push(nz); - - } - - vNode = vNode.nextElementSibling; - - } - - } - currVerticesNode = currVerticesNode.nextElementSibling; - - } - - return { "vertices": vertArray, "normals": normalArray }; - - } - - function loadObject( node ) { - - var objId = node.attributes[ 'id' ].textContent; - var loadedObject = { "name": "amfobject", "meshes": [] }; - var currColor = null; - var currObjNode = node.firstElementChild; - - while ( currObjNode ) { - - if ( currObjNode.nodeName === "metadata" ) { - - if ( currObjNode.attributes[ 'type' ] !== undefined ) { - - if ( currObjNode.attributes[ 'type' ].value === 'name' ) { - - loadedObject.name = currObjNode.textContent; - - } - - } - - } else if ( currObjNode.nodeName === "color" ) { - - currColor = loadColor( currObjNode ); - - } else if ( currObjNode.nodeName === "mesh" ) { - - var currMeshNode = currObjNode.firstElementChild; - var mesh = { "vertices": [], "normals": [], "volumes": [], "color": currColor }; - - while ( currMeshNode ) { - - if ( currMeshNode.nodeName === "vertices" ) { - - var loadedVertices = loadMeshVertices( currMeshNode ); - - mesh.normals = mesh.normals.concat( loadedVertices.normals ); - mesh.vertices = mesh.vertices.concat( loadedVertices.vertices ); - - } else if ( currMeshNode.nodeName === "volume" ) { - - mesh.volumes.push( loadMeshVolume( currMeshNode ) ); - - } - - currMeshNode = currMeshNode.nextElementSibling; - - } - - loadedObject.meshes.push( mesh ); - - } - - currObjNode = currObjNode.nextElementSibling; - - } - - return { 'id': objId, 'obj': loadedObject }; - - } - - var xmlData = loadDocument( data ); - var amfName = ""; - var amfAuthor = ""; - var amfScale = loadDocumentScale( xmlData ); - var amfMaterials = {}; - var amfObjects = {}; - var children = xmlData.documentElement.children; - - for ( var i = 0; i < children.length; i ++ ) { - - var child = children[ i ]; - - if ( child.nodeName === 'metadata' ) { - - if ( child.attributes[ 'type' ] !== undefined ) { - - if ( child.attributes[ 'type' ].value === 'name' ) { - - amfName = child.textContent; - - } else if ( child.attributes[ 'type' ].value === 'author' ) { - - amfAuthor = child.textContent; - - } - - } - - } else if ( child.nodeName === 'material' ) { - - var loadedMaterial = loadMaterials( child ); - - amfMaterials[ loadedMaterial.id ] = loadedMaterial.material; - - } else if ( child.nodeName === 'object' ) { - - var loadedObject = loadObject( child ); - - amfObjects[ loadedObject.id ] = loadedObject.obj; - - } - - } - - var sceneObject = new THREE.Group(); - var defaultMaterial = new THREE.MeshPhongMaterial( { color: 0xaaaaff, shading: THREE.FlatShading } ); - - sceneObject.name = amfName; - sceneObject.userData.author = amfAuthor; - sceneObject.userData.loader = "AMF"; - - for ( var id in amfObjects ) { - - var meshes = amfObjects[ id ].meshes; - var newObject = new THREE.Group(); - - for ( var i = 0; i < meshes.length; i ++ ) { - - var objDefaultMaterial = defaultMaterial; - var mesh = meshes[ i ]; - var meshVertices = Float32Array.from( mesh.vertices ); - var vertices = new THREE.BufferAttribute( Float32Array.from( meshVertices ), 3 ); - var meshNormals = null; - var normals = null; - - if ( mesh.normals.length ) { - - meshNormals = Float32Array.from( mesh.normals ); - normals = new THREE.BufferAttribute( Float32Array.from( meshNormals ), 3 ); - - } - - if ( mesh.color ) { - - var color = mesh.color; - - objDefaultMaterial = defaultMaterial.clone(); - objDefaultMaterial.color = new THREE.Color( color.r, color.g, color.b ); - - if ( color.a !== 1.0 ) { - - objDefaultMaterial.transparent = true; - objDefaultMaterial.opacity = color.a; - - } - - } - - var volumes = mesh.volumes; - - for ( var j = 0; j < volumes.length; j ++ ) { - - var volume = volumes[ j ]; - var newGeometry = new THREE.BufferGeometry(); - var indexes = Uint32Array.from( volume.triangles ); - var material = objDefaultMaterial; - - newGeometry.setIndex( new THREE.BufferAttribute( indexes, 1 ) ); - newGeometry.addAttribute( 'position', vertices.clone() ); - - if( normals ) { - - newGeometry.addAttribute( 'normal', normals.clone() ); - - } - - if ( amfMaterials[ volume.materialId ] !== undefined ) { - - material = amfMaterials[ volume.materialId ]; - - } - - newGeometry.scale( amfScale, amfScale, amfScale ); - newObject.add( new THREE.Mesh( newGeometry, material.clone() ) ); - - } - - } - - sceneObject.add( newObject ); - - } - - return sceneObject; - - } - -}; diff --git a/tests/3d.test.js b/tests/3d.test.js deleted file mode 100644 index c2f70c6..0000000 --- a/tests/3d.test.js +++ /dev/null @@ -1,12 +0,0 @@ -( function ( mw, $ ) { - QUnit.module( 'ext.3d' ); - - /** - * Write your QUnit tests here. For more information on - * how to write proper JavaScript QUnit tests for - * MediaWiki extension development, please read - * the manual: - * https://www.mediawiki.org/wiki/Manual:JavaScript_unit_testing#Write_a_unit_test - */ - -} )( mediaWiki, jQuery ); diff --git a/tests/3d.test.php b/tests/3d.test.php deleted file mode 100644 index b7a9013..0000000 --- a/tests/3d.test.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -/** - * For more information on how to create PHPUnit tests - * for your extension, visit the documentation page: - * https://www.mediawiki.org/wiki/Manual:PHP_unit_testing/Writing_unit_tests - */ -- To view, visit https://gerrit.wikimedia.org/r/340330 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Ifc716148ae40e87c8e9d5b650e069dee9e09d43d Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/3D Gerrit-Branch: master Gerrit-Owner: Jforrester <jforres...@wikimedia.org> Gerrit-Reviewer: MarkTraceur <mholmqu...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits