diff --git a/docs/changelog.md b/docs/changelog.md index d3e63c8ae..ddf1dd6b7 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -21,6 +21,9 @@ Requires libvips v8.15.2 * Ensure `extend` operation stays sequential for multi-page TIFF (regression in 0.32.0). [#4069](https://github.com/lovell/sharp/issues/4069) +* Tighten validation of constructor `text` integer properties. + [#4071](https://github.com/lovell/sharp/issues/4071) + ### v0.33.3 - 23rd March 2024 * Upgrade to libvips v8.15.2 for upstream bug fixes. diff --git a/lib/input.js b/lib/input.js index e212dc14e..612b03880 100644 --- a/lib/input.js +++ b/lib/input.js @@ -296,17 +296,17 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } } if (is.defined(inputOptions.text.width)) { - if (is.number(inputOptions.text.width)) { + if (is.integer(inputOptions.text.width) && inputOptions.text.width > 0) { inputDescriptor.textWidth = inputOptions.text.width; } else { - throw is.invalidParameterError('text.textWidth', 'number', inputOptions.text.width); + throw is.invalidParameterError('text.width', 'positive integer', inputOptions.text.width); } } if (is.defined(inputOptions.text.height)) { - if (is.number(inputOptions.text.height)) { + if (is.integer(inputOptions.text.height) && inputOptions.text.height > 0) { inputDescriptor.textHeight = inputOptions.text.height; } else { - throw is.invalidParameterError('text.height', 'number', inputOptions.text.height); + throw is.invalidParameterError('text.height', 'positive integer', inputOptions.text.height); } } if (is.defined(inputOptions.text.align)) { @@ -324,10 +324,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } } if (is.defined(inputOptions.text.dpi)) { - if (is.number(inputOptions.text.dpi) && is.inRange(inputOptions.text.dpi, 1, 100000)) { + if (is.integer(inputOptions.text.dpi) && is.inRange(inputOptions.text.dpi, 1, 1000000)) { inputDescriptor.textDpi = inputOptions.text.dpi; } else { - throw is.invalidParameterError('text.dpi', 'number between 1 and 100000', inputOptions.text.dpi); + throw is.invalidParameterError('text.dpi', 'integer between 1 and 1000000', inputOptions.text.dpi); } } if (is.defined(inputOptions.text.rgba)) { @@ -338,10 +338,10 @@ function _createInputDescriptor (input, inputOptions, containerOptions) { } } if (is.defined(inputOptions.text.spacing)) { - if (is.number(inputOptions.text.spacing)) { + if (is.integer(inputOptions.text.spacing) && is.inRange(inputOptions.text.spacing, -1000000, 1000000)) { inputDescriptor.textSpacing = inputOptions.text.spacing; } else { - throw is.invalidParameterError('text.spacing', 'number', inputOptions.text.spacing); + throw is.invalidParameterError('text.spacing', 'integer between -1000000 and 1000000', inputOptions.text.spacing); } } if (is.defined(inputOptions.text.wrap)) { diff --git a/test/unit/text.js b/test/unit/text.js index d404ac8bb..a81a88c93 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -228,26 +228,34 @@ describe('Text to image', function () { }); }); - it('bad width input', function () { - assert.throws(function () { - sharp({ - text: { - text: 'text', - width: 'bad' - } - }); - }); + it('invalid width', () => { + assert.throws( + () => sharp({ text: { text: 'text', width: 'bad' } }), + /Expected positive integer for text\.width but received bad of type string/ + ); + assert.throws( + () => sharp({ text: { text: 'text', width: 0.1 } }), + /Expected positive integer for text\.width but received 0.1 of type number/ + ); + assert.throws( + () => sharp({ text: { text: 'text', width: -1 } }), + /Expected positive integer for text\.width but received -1 of type number/ + ); }); - it('bad height input', function () { - assert.throws(function () { - sharp({ - text: { - text: 'text', - height: 'bad' - } - }); - }); + it('invalid height', () => { + assert.throws( + () => sharp({ text: { text: 'text', height: 'bad' } }), + /Expected positive integer for text\.height but received bad of type string/ + ); + assert.throws( + () => sharp({ text: { text: 'text', height: 0.1 } }), + /Expected positive integer for text\.height but received 0.1 of type number/ + ); + assert.throws( + () => sharp({ text: { text: 'text', height: -1 } }), + /Expected positive integer for text\.height but received -1 of type number/ + ); }); it('bad align input', function () { @@ -272,15 +280,19 @@ describe('Text to image', function () { }); }); - it('bad dpi input', function () { - assert.throws(function () { - sharp({ - text: { - text: 'text', - dpi: -10 - } - }); - }); + it('invalid dpi', () => { + assert.throws( + () => sharp({ text: { text: 'text', dpi: 'bad' } }), + /Expected integer between 1 and 1000000 for text\.dpi but received bad of type string/ + ); + assert.throws( + () => sharp({ text: { text: 'text', dpi: 0.1 } }), + /Expected integer between 1 and 1000000 for text\.dpi but received 0.1 of type number/ + ); + assert.throws( + () => sharp({ text: { text: 'text', dpi: -1 } }), + /Expected integer between 1 and 1000000 for text\.dpi but received -1 of type number/ + ); }); it('bad rgba input', function () { @@ -294,15 +306,19 @@ describe('Text to image', function () { }); }); - it('bad spacing input', function () { - assert.throws(function () { - sharp({ - text: { - text: 'text', - spacing: 'number expected' - } - }); - }); + it('invalid spacing', () => { + assert.throws( + () => sharp({ text: { text: 'text', spacing: 'bad' } }), + /Expected integer between -1000000 and 1000000 for text\.spacing but received bad of type string/ + ); + assert.throws( + () => sharp({ text: { text: 'text', spacing: 0.1 } }), + /Expected integer between -1000000 and 1000000 for text\.spacing but received 0.1 of type number/ + ); + assert.throws( + () => sharp({ text: { text: 'text', spacing: -1000001 } }), + /Expected integer between -1000000 and 1000000 for text\.spacing but received -1000001 of type number/ + ); }); it('only height or dpi not both', function () {