Skip to content

Commit

Permalink
Expose ability to (un)block libvips ops by name
Browse files Browse the repository at this point in the history
  • Loading branch information
lovell committed Jul 19, 2023
1 parent a0e1c39 commit 739b317
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 1 deletion.
55 changes: 55 additions & 0 deletions docs/api-utility.md
Expand Up @@ -165,4 +165,59 @@ const simd = sharp.simd();
```js
const simd = sharp.simd(false);
// prevent libvips from using liborc at runtime
```


## block
Block libvips operations at runtime.

This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
which when set will block all "untrusted" operations.


**Since**: 0.32.4

| Param | Type | Description |
| --- | --- | --- |
| options | <code>Object</code> | |
| options.operation | <code>Array.&lt;string&gt;</code> | List of libvips low-level operation names to block. |

**Example** *(Block all TIFF input.)*
```js
sharp.block({
operation: ['VipsForeignLoadTiff']
});
```


## unblock
Unblock libvips operations at runtime.

This is useful for defining a list of allowed operations.


**Since**: 0.32.4

| Param | Type | Description |
| --- | --- | --- |
| options | <code>Object</code> | |
| options.operation | <code>Array.&lt;string&gt;</code> | List of libvips low-level operation names to unblock. |

**Example** *(Block all input except WebP from the filesystem.)*
```js
sharp.block({
operation: ['VipsForeignLoad']
});
sharp.unblock({
operation: ['VipsForeignLoadWebpFile']
});
```
**Example** *(Block all input except JPEG and PNG from a Buffer or Stream.)*
```js
sharp.block({
operation: ['VipsForeignLoad']
});
sharp.unblock({
operation: ['VipsForeignLoadJpegBuffer', 'VipsForeignLoadPngBuffer']
});
```
4 changes: 4 additions & 0 deletions docs/changelog.md
Expand Up @@ -4,6 +4,10 @@

Requires libvips v8.14.2

### v0.32.4 - TBD

* Expose ability to (un)block low-level libvips operations by name.

### v0.32.3 - 14th July 2023

* Expose `preset` option for WebP output.
Expand Down
2 changes: 1 addition & 1 deletion docs/search-index.json

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions lib/utility.js
Expand Up @@ -202,6 +202,72 @@ function simd (simd) {
}
simd(true);

/**
* Block libvips operations at runtime.
*
* This is in addition to the `VIPS_BLOCK_UNTRUSTED` environment variable,
* which when set will block all "untrusted" operations.
*
* @since 0.32.4
*
* @example <caption>Block all TIFF input.</caption>
* sharp.block({
* operation: ['VipsForeignLoadTiff']
* });
*
* @param {Object} options
* @param {Array<string>} options.operation - List of libvips low-level operation names to block.
*/
function block (options) {
if (is.object(options)) {
if (Array.isArray(options.operation) && options.operation.every(is.string)) {
sharp.block(options.operation, true);
} else {
throw is.invalidParameterError('operation', 'Array<string>', options.operation);
}
} else {
throw is.invalidParameterError('options', 'object', options);
}
}

/**
* Unblock libvips operations at runtime.
*
* This is useful for defining a list of allowed operations.
*
* @since 0.32.4
*
* @example <caption>Block all input except WebP from the filesystem.</caption>
* sharp.block({
* operation: ['VipsForeignLoad']
* });
* sharp.unblock({
* operation: ['VipsForeignLoadWebpFile']
* });
*
* @example <caption>Block all input except JPEG and PNG from a Buffer or Stream.</caption>
* sharp.block({
* operation: ['VipsForeignLoad']
* });
* sharp.unblock({
* operation: ['VipsForeignLoadJpegBuffer', 'VipsForeignLoadPngBuffer']
* });
*
* @param {Object} options
* @param {Array<string>} options.operation - List of libvips low-level operation names to unblock.
*/
function unblock (options) {
if (is.object(options)) {
if (Array.isArray(options.operation) && options.operation.every(is.string)) {
sharp.block(options.operation, false);
} else {
throw is.invalidParameterError('operation', 'Array<string>', options.operation);
}
} else {
throw is.invalidParameterError('options', 'object', options);
}
}

/**
* Decorate the Sharp class with utility-related functions.
* @private
Expand All @@ -216,4 +282,6 @@ module.exports = function (Sharp) {
Sharp.versions = versions;
Sharp.vendor = vendor;
Sharp.queue = queue;
Sharp.block = block;
Sharp.unblock = unblock;
};
1 change: 1 addition & 0 deletions src/sharp.cc
Expand Up @@ -31,6 +31,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
exports.Set("simd", Napi::Function::New(env, simd));
exports.Set("libvipsVersion", Napi::Function::New(env, libvipsVersion));
exports.Set("format", Napi::Function::New(env, format));
exports.Set("block", Napi::Function::New(env, block));
exports.Set("_maxColourDistance", Napi::Function::New(env, _maxColourDistance));
exports.Set("_isUsingJemalloc", Napi::Function::New(env, _isUsingJemalloc));
exports.Set("stats", Napi::Function::New(env, stats));
Expand Down
11 changes: 11 additions & 0 deletions src/utilities.cc
Expand Up @@ -164,6 +164,17 @@ Napi::Value format(const Napi::CallbackInfo& info) {
return format;
}

/*
(Un)block libvips operations at runtime.
*/
void block(const Napi::CallbackInfo& info) {
Napi::Array ops = info[size_t(0)].As<Napi::Array>();
bool const state = info[size_t(1)].As<Napi::Boolean>().Value();
for (unsigned int i = 0; i < ops.Length(); i++) {
vips_operation_block_set(ops.Get(i).As<Napi::String>().Utf8Value().c_str(), state);
}
}

/*
Synchronous, internal-only method used by some of the functional tests.
Calculates the maximum colour distance using the DE2000 algorithm
Expand Down
1 change: 1 addition & 0 deletions src/utilities.h
Expand Up @@ -12,6 +12,7 @@ Napi::Value counters(const Napi::CallbackInfo& info);
Napi::Value simd(const Napi::CallbackInfo& info);
Napi::Value libvipsVersion(const Napi::CallbackInfo& info);
Napi::Value format(const Napi::CallbackInfo& info);
void block(const Napi::CallbackInfo& info);
Napi::Value _maxColourDistance(const Napi::CallbackInfo& info);
Napi::Value _isUsingJemalloc(const Napi::CallbackInfo& info);

Expand Down
37 changes: 37 additions & 0 deletions test/unit/util.js
Expand Up @@ -153,4 +153,41 @@ describe('Utilities', function () {
assert.strictEqual(true, Array.isArray(sharp.vendor.installed));
});
});

describe('Block', () => {
it('Can block a named operation', () => {
sharp.block({ operation: ['test'] });
});
it('Can unblock a named operation', () => {
sharp.unblock({ operation: ['test'] });
});
it('Invalid block operation throws', () => {
assert.throws(() => sharp.block(1),
/Expected object for options but received 1 of type number/
);
assert.throws(() => sharp.block({}),
/Expected Array<string> for operation but received undefined of type undefined/
);
assert.throws(() => sharp.block({ operation: 'fail' }),
/Expected Array<string> for operation but received fail of type string/
);
assert.throws(() => sharp.block({ operation: ['maybe', false] }),
/Expected Array<string> for operation but received maybe,false of type object/
);
});
it('Invalid unblock operation throws', () => {
assert.throws(() => sharp.unblock(1),
/Expected object for options but received 1 of type number/
);
assert.throws(() => sharp.unblock({}),
/Expected Array<string> for operation but received undefined of type undefined/
);
assert.throws(() => sharp.unblock({ operation: 'fail' }),
/Expected Array<string> for operation but received fail of type string/
);
assert.throws(() => sharp.unblock({ operation: ['maybe', false] }),
/Expected Array<string> for operation but received maybe,false of type object/
);
});
});
});

0 comments on commit 739b317

Please sign in to comment.