mirror of
https://github.com/CesiumGS/obj2gltf.git
synced 2024-11-23 08:34:14 -05:00
Add secure checking of paths
This commit is contained in:
parent
e4b3ad5409
commit
3c958e1d86
@ -49,6 +49,7 @@ Using obj2gltf as a command-line tool:
|
||||
|`--ao`|Apply ambient occlusion to the converted model.|No, default `false`|
|
||||
|`--bypassPipeline`|Bypass the gltf-pipeline for debugging purposes. This option overrides many of the options above and will save the glTF with the KHR_materials_common extension.|No, default `false`|
|
||||
|`--hasTransparency`|Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures with an alpha channel are considered to be transparent.|No, default `false`|
|
||||
|`--secure`|Prevent the converter from reading image or mtl files outside of the input obj directory.|No, default `false`|
|
||||
|
||||
## Build Instructions
|
||||
|
||||
|
@ -84,6 +84,11 @@ var argv = yargs
|
||||
describe: 'Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel. By default textures with an alpha channel are considered to be transparent.',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
},
|
||||
secure : {
|
||||
describe: 'Prevent the converter from reading image or mtl files outside of the input obj directory.',
|
||||
type: 'boolean',
|
||||
default: false
|
||||
}
|
||||
}).parse(args);
|
||||
|
||||
@ -111,7 +116,8 @@ var options = {
|
||||
ao : argv.ao,
|
||||
optimizeForCesium : argv.cesium,
|
||||
bypassPipeline : argv.bypassPipeline,
|
||||
hasTransparency : argv.hasTransparency
|
||||
hasTransparency : argv.hasTransparency,
|
||||
secure : argv.secure
|
||||
};
|
||||
|
||||
console.time('Total');
|
||||
|
@ -33,6 +33,7 @@ module.exports = convert;
|
||||
* @param {Boolean} [options.textureCompressionOptions] Options sent to the compressTextures stage of gltf-pipeline.
|
||||
* @param {Boolean} [options.bypassPipeline=false] Bypass the gltf-pipeline for debugging purposes. This option overrides many of the options above and will save the glTF with the KHR_materials_common extension.
|
||||
* @param {Boolean} [options.hasTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||
* @param {Boolean} [options.secure=false] Prevent the converter from reading image or mtl files outside of the input obj directory.
|
||||
*/
|
||||
|
||||
function convert(objPath, gltfPath, options) {
|
||||
|
@ -56,10 +56,6 @@ function loadImage(imagePath, options) {
|
||||
}
|
||||
|
||||
return info;
|
||||
})
|
||||
.catch(function() {
|
||||
console.log('Could not read image file at ' + imagePath + '. Material will ignore this image.');
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -101,10 +101,6 @@ function loadMtl(mtlPath) {
|
||||
return readLines(mtlPath, parseLine)
|
||||
.then(function() {
|
||||
return materials;
|
||||
})
|
||||
.catch(function() {
|
||||
console.log('Could not read material file at ' + mtlPath + '. Using default material instead.');
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
|
33
lib/obj.js
33
lib/obj.js
@ -53,12 +53,18 @@ var facePattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(
|
||||
* @param {String} objPath Path to the obj file.
|
||||
* @param {Object} [options] An object with the following properties:
|
||||
* @param {Boolean} [options.hasTransparency=false] Do a more exhaustive check for texture transparency by looking at the alpha channel of each pixel.
|
||||
* @param {Boolean} [options.secure=false] Prevent the converter from reading image or mtl files outside of the input obj directory.
|
||||
* @returns {Promise} A promise resolving to the obj data.
|
||||
* @exception {RuntimeError} The file does not have any geometry information in it.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function loadObj(objPath, options) {
|
||||
options = combine(options, {
|
||||
hasTransparency : false,
|
||||
secure : false
|
||||
});
|
||||
|
||||
// Global store of vertex attributes listed in the obj file
|
||||
var positions = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
var normals = new ArrayStorage(ComponentDatatype.FLOAT);
|
||||
@ -284,10 +290,10 @@ function finishLoading(nodes, mtlPaths, objPath, options) {
|
||||
if (nodes.length === 0) {
|
||||
throw new RuntimeError(objPath + ' does not have any geometry data');
|
||||
}
|
||||
return loadMaterials(mtlPaths, objPath)
|
||||
return loadMaterials(mtlPaths, objPath, options)
|
||||
.then(function(materials) {
|
||||
var imagePaths = getImagePaths(materials);
|
||||
return loadImages(imagePaths, options)
|
||||
return loadImages(imagePaths, objPath, options)
|
||||
.then(function(images) {
|
||||
return {
|
||||
nodes : nodes,
|
||||
@ -305,27 +311,46 @@ function getAbsolutePath(mtlPath, objPath) {
|
||||
return mtlPath;
|
||||
}
|
||||
|
||||
function loadMaterials(mtlPaths, objPath) {
|
||||
function outsideDirectory(filePath, objPath) {
|
||||
return (path.relative(path.dirname(objPath), filePath).indexOf('..') === 0);
|
||||
}
|
||||
|
||||
function loadMaterials(mtlPaths, objPath, options) {
|
||||
var materials = {};
|
||||
return Promise.map(mtlPaths, function(mtlPath) {
|
||||
mtlPath = getAbsolutePath(mtlPath, objPath);
|
||||
if (options.secure && outsideDirectory(mtlPath, objPath)) {
|
||||
console.log('Could not read mtl file at ' + mtlPath + ' because it is outside of the obj directory and the secure flag is true. Using default material instead.');
|
||||
return;
|
||||
}
|
||||
return loadMtl(mtlPath)
|
||||
.then(function(materialsInMtl) {
|
||||
materials = combine(materials, materialsInMtl);
|
||||
})
|
||||
.catch(function() {
|
||||
console.log('Could not read mtl file at ' + mtlPath + '. Using default material instead.');
|
||||
});
|
||||
}).then(function() {
|
||||
return materials;
|
||||
});
|
||||
}
|
||||
|
||||
function loadImages(imagePaths, options) {
|
||||
function loadImages(imagePaths, objPath, options) {
|
||||
var images = {};
|
||||
return Promise.map(imagePaths, function(imagePath) {
|
||||
if (options.secure && outsideDirectory(imagePath, objPath)) {
|
||||
console.log('Could not read image file at ' + imagePath + ' because it is outside of the obj directory and the secure flag is true. Material will ignore this image.');
|
||||
return;
|
||||
}
|
||||
return loadImage(imagePath, options)
|
||||
.then(function(image) {
|
||||
if (defined(image)) {
|
||||
images[imagePath] = image;
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
console.log('Could not read image file at ' + imagePath + '. Material will ignore this image.');
|
||||
return undefined;
|
||||
});
|
||||
}).then(function() {
|
||||
return images;
|
||||
|
@ -91,13 +91,4 @@ describe('image', function() {
|
||||
expect(info.transparent).toBe(false);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
it('handles invalid image file', function(done) {
|
||||
spyOn(console, 'log');
|
||||
expect(loadImage(invalidImage)
|
||||
.then(function(image) {
|
||||
expect(image).toBeUndefined();
|
||||
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read image file') >= 0).toBe(true);
|
||||
}), done).toResolve();
|
||||
});
|
||||
});
|
||||
|
@ -41,13 +41,4 @@ describe('mtl', function() {
|
||||
expect(materials.Blue.diffuseColor).toEqual([0.0, 0.0, 0.64, 1.0]);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
it('handles invalid mtl file', function(done) {
|
||||
spyOn(console, 'log');
|
||||
expect(loadMtl(invalidMaterialUrl)
|
||||
.then(function(materials) {
|
||||
expect(materials).toEqual({});
|
||||
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read material file') >= 0).toBe(true);
|
||||
}), done).toResolve();
|
||||
});
|
||||
});
|
||||
|
@ -21,6 +21,7 @@ var objMultipleMaterialsUrl = 'specs/data/box-multiple-materials/box-multiple-ma
|
||||
var objUncleanedUrl = 'specs/data/box-uncleaned/box-uncleaned.obj';
|
||||
var objMtllibUrl = 'specs/data/box-mtllib/box-mtllib.obj';
|
||||
var objMissingMtllibUrl = 'specs/data/box-missing-mtllib/box-missing-mtllib.obj';
|
||||
var objExternalResourcesUrl = 'specs/data/box-external-resources/box-external-resources.obj';
|
||||
var objTexturedUrl = 'specs/data/box-textured/box-textured.obj';
|
||||
var objMissingTextureUrl = 'specs/data/box-missing-texture/box-missing-texture.obj';
|
||||
var objSubdirectoriesUrl = 'specs/data/box-subdirectories/box-textured.obj';
|
||||
@ -269,6 +270,32 @@ describe('obj', function() {
|
||||
expect(loadObj(objMissingMtllibUrl)
|
||||
.then(function(data) {
|
||||
expect(data.materials).toEqual({});
|
||||
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
it('loads resources outside of the obj directory', function(done) {
|
||||
expect(loadObj(objExternalResourcesUrl)
|
||||
.then(function(data) {
|
||||
var imagePath = getImagePath(objTexturedUrl, 'cesium.png');
|
||||
expect(data.images[imagePath]).toBeDefined();
|
||||
expect(data.materials.MaterialTextured.diffuseColorMap).toEqual(imagePath);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
it('does not load resources outside of the obj directory when secure is true', function(done) {
|
||||
spyOn(console, 'log');
|
||||
var options = {
|
||||
secure : true
|
||||
};
|
||||
expect(loadObj(objExternalResourcesUrl, options)
|
||||
.then(function(data) {
|
||||
var imagePath = getImagePath(objMissingTextureUrl, 'cesium.png');
|
||||
expect(data.images[imagePath]).toBeUndefined();
|
||||
expect(data.materials.MaterialTextured).toBeDefined();
|
||||
expect(data.materials.Material).toBeUndefined(); // Not in directory, so not included
|
||||
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read mtl file') >= 0).toBe(true);
|
||||
expect(console.log.calls.argsFor(1)[0].indexOf('Could not read image file') >= 0).toBe(true);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
@ -288,6 +315,7 @@ describe('obj', function() {
|
||||
var imagePath = getImagePath(objMissingTextureUrl, 'cesium.png');
|
||||
expect(data.images[imagePath]).toBeUndefined();
|
||||
expect(data.materials.Material.diffuseColorMap).toEqual(imagePath);
|
||||
expect(console.log.calls.argsFor(0)[0].indexOf('Could not read image file') >= 0).toBe(true);
|
||||
}), done).toResolve();
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user