Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

inert

Package Overview
Dependencies
Maintainers
5
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

inert - npm Package Compare versions

Comparing version 5.0.1 to 5.1.0

175

lib/directory.js

@@ -34,27 +34,40 @@ 'use strict';

exports.handler = function (route, options) {
internals.normalizePaths = function (basePath, paths) {
const settings = Joi.attempt(options, internals.schema, 'Invalid directory handler options (' + route.path + ')');
Hoek.assert(route.path[route.path.length - 1] === '}', 'The route path for a directory handler must end with a parameter:', route.path);
return paths.map((path) => {
const paramName = /\w+/.exec(route.path.slice(route.path.lastIndexOf('{')))[0];
return Path.isAbsolute(path) ? path : Path.join(basePath, path);
});
};
const normalize = (paths) => {
const normalized = [];
for (let i = 0; i < paths.length; ++i) {
let path = paths[i];
internals.resolvePathOption = function (basePath, result) {
if (!Path.isAbsolute(path)) {
path = Path.join(route.settings.files.relativeTo, path);
}
if (result instanceof Error) {
throw result;
}
normalized.push(path);
}
let paths;
if (typeof result === 'string') {
paths = [result];
}
else if (Array.isArray(result)) {
paths = result;
}
else {
throw Boom.internal('Invalid path function');
}
return normalized;
};
return internals.normalizePaths(basePath, paths);
};
const normalized = (Array.isArray(settings.path) ? normalize(settings.path) : []); // Array or function
exports.handler = function (route, options) {
const settings = Joi.attempt(options, internals.schema, 'Invalid directory handler options (' + route.path + ')');
Hoek.assert(route.path[route.path.length - 1] === '}', 'The route path for a directory handler must end with a parameter:', route.path);
const paramName = /\w+/.exec(route.path.slice(route.path.lastIndexOf('{')))[0];
const basePath = route.settings.files.relativeTo;
const normalized = (Array.isArray(settings.path) ? internals.normalizePaths(basePath, settings.path) : null); // Array or function
const indexNames = (settings.index === true) ? ['index.html'] : (settings.index || []);

@@ -66,20 +79,4 @@

let paths = normalized;
if (typeof settings.path === 'function') {
const result = settings.path.call(null, request);
if (result instanceof Error) {
throw result;
}
const paths = normalized || internals.resolvePathOption(basePath, settings.path.call(null, request));
if (Array.isArray(result)) {
paths = normalize(result);
}
else if (typeof result === 'string') {
paths = normalize([result]);
}
else {
throw Boom.badImplementation('Invalid path function');
}
}
// Append parameter

@@ -92,3 +89,3 @@

throw Boom.notFound();
throw Boom.notFound(null, {});
}

@@ -122,81 +119,69 @@

// Not found
// Handle Not found
if (error.output.statusCode === 404) {
if (settings.defaultExtension) {
if (hasTrailingSlash) {
path = path.slice(0, -1);
}
if (internals.isNotFound(error)) {
if (!settings.defaultExtension) {
throw error;
}
try {
return await File.load(path + '.' + settings.defaultExtension, request, fileOptions);
}
catch (err) {
Bounce.ignore(err, 'boom');
}
if (hasTrailingSlash) {
path = path.slice(0, -1);
}
return;
return await File.load(path + '.' + settings.defaultExtension, request, fileOptions);
}
// Propagate non-directory errors
// Handle Directory
if (error.output.statusCode !== 403 ||
error.data !== 'EISDIR') {
if (internals.isDirectory(error)) {
if (settings.redirectToSlash !== false && // Defaults to true
!request.server.settings.router.stripTrailingSlash &&
!hasTrailingSlash) {
throw error;
}
return reply.redirect(resource + '/');
}
// Directory
for (const indexName of indexNames) {
const indexFile = Path.join(path, indexName);
try {
return await File.load(indexFile, request, fileOptions);
}
catch (err) {
Bounce.ignore(err, 'boom');
if (!indexNames.length &&
!settings.listing) {
if (!internals.isNotFound(err)) {
throw Boom.internal(indexName + ' is a directory', err);
}
throw Boom.forbidden();
}
if (settings.redirectToSlash !== false && // Defaults to true
!request.server.settings.router.stripTrailingSlash &&
!hasTrailingSlash) {
return reply.redirect(resource + '/');
}
for (let i = 0; i < indexNames.length; ++i) {
const indexName = indexNames[i];
const indexFile = Path.join(path, indexName);
try {
// File loaded successfully
return await File.load(indexFile, request, fileOptions);
// Not found - try next
}
}
catch (err) {
Bounce.ignore(err, 'boom');
// Directory
// None of the index files were found
if (err.output.statusCode !== 404) {
throw Boom.badImplementation(indexName + ' is a directory');
}
if (settings.listing) {
return internals.generateListing(Path.join(baseDir, path), resource, selection, hasTrailingSlash, settings, request);
}
}
// None of the index files were found
throw error;
};
if (!settings.listing) {
throw Boom.forbidden();
for (let i = 0; i < paths.length; ++i) {
try {
return await each(paths[i]);
}
catch (err) {
Bounce.ignore(err, 'boom');
return await internals.generateListing(Path.join(baseDir, path), resource, selection, hasTrailingSlash, settings, request);
};
// Propagate any non-404 errors
for (let i = 0; i < paths.length; ++i) {
const response = await each(paths[i]);
if (response !== undefined) {
return response;
if (!internals.isNotFound(err) ||
i === paths.length - 1) {
throw err;
}
}
}
throw Boom.notFound();
throw Boom.notFound(null, {});
};

@@ -252,1 +237,13 @@

};
internals.isNotFound = function (boom) {
return boom.output.statusCode === 404;
};
internals.isDirectory = function (boom) {
return boom.output.statusCode === 403 && boom.data.code === 'EISDIR';
};

@@ -88,3 +88,3 @@ 'use strict';

Bounce.rethrow(err, 'system');
throw Boom.boomify(err, { message: 'Failed to hash file' });
throw Boom.boomify(err, { message: 'Failed to hash file', data: { path: response.source.path } });
}

@@ -91,0 +91,0 @@ };

@@ -104,3 +104,3 @@ 'use strict';

if (path === null) {
throw Boom.forbidden(null, 'EACCES');
throw Boom.forbidden(null, { code: 'EACCES' });
}

@@ -154,9 +154,9 @@

if (extension) {
const gzFile = new Fs.File(`${response.source.path}${extension}`);
const precompressed = new Fs.File(`${response.source.path}${extension}`);
let stat;
try {
stat = await gzFile.openStat('r');
stat = await precompressed.openStat('r');
}
catch (err) {
gzFile.close();
precompressed.close();
Bounce.ignore(err, 'boom');

@@ -167,3 +167,3 @@ }

response.source.file.close();
response.source.file = gzFile;
response.source.file = precompressed;

@@ -170,0 +170,0 @@ response.bytes(stat.size);

@@ -37,11 +37,14 @@ 'use strict';

catch (err) {
const data = { path: this.path };
if (this.path.indexOf('\u0000') !== -1 || err.code === 'ENOENT') {
throw Boom.notFound();
throw Boom.notFound(null, data);
}
if (err.code === 'EACCES' || err.code === 'EPERM') {
throw Boom.forbidden(null, err.code);
data.code = err.code;
throw Boom.forbidden(null, data);
}
throw Boom.boomify(err, { message: 'Failed to open file' });
throw Boom.boomify(err, { message: 'Failed to open file', data });
}

@@ -54,3 +57,3 @@ };

if (this.fd !== null) {
exports.close(this.fd).then(null, Hoek.ignore);
Bounce.background(exports.close(this.fd));
this.fd = null;

@@ -69,3 +72,3 @@ }

if (stat.isDirectory()) {
throw Boom.forbidden(null, 'EISDIR');
throw Boom.forbidden(null, { code: 'EISDIR', path: this.path });
}

@@ -79,3 +82,3 @@

Bounce.rethrow(err, ['boom', 'system']);
throw Boom.boomify(err, { message: 'Failed to stat file' });
throw Boom.boomify(err, { message: 'Failed to stat file', data: { path: this.path } });
}

@@ -82,0 +85,0 @@ };

@@ -21,2 +21,18 @@ 'use strict';

internals.fileMethod = function (path, responseOptions) {
// Set correct confine value
responseOptions = responseOptions || {};
if (typeof responseOptions.confine === 'undefined' || responseOptions.confine === true) {
responseOptions.confine = '.';
}
Hoek.assert(responseOptions.end === undefined || +responseOptions.start <= +responseOptions.end, 'options.start must be less than or equal to options.end');
return this.response(File.response(path, responseOptions, this.request));
};
exports.plugin = {

@@ -35,17 +51,4 @@ pkg: require('../package.json'),

server.decorate('handler', 'directory', Directory.handler);
server.decorate('toolkit', 'file', function (path, responseOptions) {
// Set correct confine value
responseOptions = responseOptions || {};
if (typeof responseOptions.confine === 'undefined' || responseOptions.confine === true) {
responseOptions.confine = '.';
}
Hoek.assert(responseOptions.end === undefined || +responseOptions.start <= +responseOptions.end, 'options.start must be less than or equal to options.end');
return this.response(File.response(path, responseOptions, this.request));
});
server.decorate('toolkit', 'file', internals.fileMethod);
}
};
{
"name": "inert",
"description": "Static file and directory handlers plugin for hapi.js",
"version": "5.0.1",
"version": "5.1.0",
"repository": "https://github.com/hapijs/inert.git",

@@ -18,3 +18,3 @@ "main": "lib/index.js",

"peerDependencies": {
"hapi": "17.x.x"
"hapi": ">=17.0.0"
},

@@ -21,0 +21,0 @@ "dependencies": {

@@ -32,2 +32,3 @@ # inert

- [The `directory` handler](#the-directory-handler)
- [Errors](#errors)

@@ -262,1 +263,14 @@ ## Examples

not found. Defaults to no extension.
### Errors
Any file access errors are signalled using appropriate [Boom](https://github.com/hapijs/boom)
errors. These are `Boom.notFound()` for missing or hidden files, and `Boom.forbidden()` for
files that exist, but can't otherwise be accessed.
The error can contain an `err.data.path` property, which is the path that the error failed for.
This property *does not always exist* if the response was generated without a file system lookup,
and for the directory handler it will be the last tested non-index path.
If an unexpected configuration or processing errors occurs, `Boom.internal()` and `'system'`
errors can also be thrown.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc