CVE-2018-3717: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: connect node module before 2.14.0 suffers from a Cross-Site Scripting (XSS) vulnerability due to a lack of validation of file in directory.js middleware.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 5.4
Published: 2018-06-07T02:29Z
Repository: https://github.com/senchalabs/connect
Language: JavaScript
Files changed: History.md, lib/index.js, lib/middleware/directory.js, package.json
Commit date: 2014-03-05 19:15:43 -0500
Commit message: directory: use serve-index

Diff: diff --git a/History.md b/History.md
index ef192a8..4b3b51e 100644
--- a/History.md
+++ b/History.md
@@ -4,10 +4,11 @@ HEAD
  * basicAuth: use basic-auth-connect
  * cookieParser: use cookie-parser
  * compress: use compression
  * csrf: use csurf
  * dep: cookie-signature@1.0.3
+ * directory: use serve-index
  * errorHandler: use errorhandler
  * favicon: use static-favicon
  * logger: use morgan
  * methodOverride: use method-override
  * responseTime: use response-time
diff --git a/lib/index.js b/lib/index.js
index 06b9c27..baa4af8 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -21,10 +21,11 @@
  *
  *  - [basicAuth](https://github.com/expressjs/basic-auth-connect) basic http authentication
  *  - [cookieParser](https://github.com/expressjs/cookie-parser) cookie parser
  *  - [compress](https://github.com/expressjs/compression) Gzip compression middleware
  *  - [csrf](https://github.com/expressjs/csurf) Cross-site request forgery protection
+ *  - [directory](https://github.com/expressjs/serve-index) directory listing middleware
  *  - [errorHandler](https://github.com/expressjs/errorhandler) flexible error handler
  *  - [favicon](https://github.com/expressjs/favicon) efficient favicon server (with default icon)
  *  - [logger](https://github.com/expressjs/morgan) request logger with custom format support
  *  - [methodOverride](https://github.com/expressjs/method-override) faux HTTP method support
  *  - [responseTime](https://github.com/expressjs/response-time) calculates response-time and exposes via X-Response-Time
@@ -36,11 +37,10 @@
  *  - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser
  *  - [multipart](multipart.html) multipart/form-data parser
  *  - [cookieSession](cookieSession.html) cookie-based session support
  *  - [staticCache](staticCache.html) memory cache layer for the static() middleware
  *  - [static](static.html) streaming static file server supporting `Range` and more
- *  - [directory](directory.html) directory listing middleware
  *  - [limit](limit.html) limit the bytesize of request bodies
  *  - [query](query.html) automatic querystring parser, populating `req.query`
  *
  * Links:
  *
diff --git a/lib/middleware/directory.js b/lib/middleware/directory.js
index 5ccff43..01cc7f5 100644
--- a/lib/middleware/directory.js
+++ b/lib/middleware/directory.js
@@ -4,340 +4,17 @@
  * Copyright(c) 2011 Sencha Inc.
  * Copyright(c) 2011 TJ Holowaychuk
  * MIT Licensed
  */
 
-// TODO: arrow key navigation
-// TODO: make icons extensible
-
-/**
- * Module dependencies.
- */
-
-var fs = require('fs')
-  , parse = require('url').parse
-  , utils = require('../utils')
-  , path = require('path')
-  , normalize = path.normalize
-  , sep = path.sep
-  , extname = path.extname
-  , join = path.join;
-var Batch = require('batch');
-var Negotiator = require('negotiator');
-
-/*!
- * Icon cache.
- */
-
-var cache = {};
-
-/*!
- * Default template.
- */
-
-var defaultTemplate = join(__dirname, '..', 'public', 'directory.html');
-
-/**
- * Media types and the map for content negotiation.
- */
-
-var mediaTypes = [
-  'text/html',
-  'text/plain',
-  'application/json'
-];
-
-var mediaType = {
-  'text/html': 'html',
-  'text/plain': 'plain',
-  'application/json': 'json'
-};
-
 /**
  * Directory:
  *
- * Serve directory listings with the given `root` path.
- *
- * Options:
- *
- *  - `hidden` display hidden (dot) files. Defaults to false.
- *  - `icons`  display icons. Defaults to false.
- *  - `filter` Apply this filter function to files. Defaults to false.
- *  - `template` Optional path to html template. Defaults to a built-in template.
- *    The following tokens are replaced:
- *      - `{directory}` with the name of the directory.
- *      - `{files}` with the HTML of an unordered list of file links.
- *      - `{linked-path}` with the HTML of a link to the directory.
- *      - `{style}` with the built-in CSS and embedded images.
+ * See [serve-index](https://github.com/expressjs/serve-index)
  *
  * @param {String} root
  * @param {Object} options
  * @return {Function}
  * @api public
  */
 
-exports = module.exports = function directory(root, options){
-  options = options || {};
-
-  // root required
-  if (!root) throw new Error('directory() root path required');
-  var hidden = options.hidden
-    , icons = options.icons
-    , view = options.view || 'tiles'
-    , filter = options.filter
-    , root = normalize(root + sep)
-    , template = options.template || defaultTemplate;
-
-  return function directory(req, res, next) {
-    if ('GET' != req.method && 'HEAD' != req.method) return next();
-
-    var url = parse(req.url)
-      , dir = decodeURIComponent(url.pathname)
-      , path = normalize(join(root, dir))
-      , originalUrl = parse(req.originalUrl)
-      , originalDir = decodeURIComponent(originalUrl.pathname)
-      , showUp = path != root;
-
-    // null byte(s), bad request
-    if (~path.indexOf('\0')) return next(utils.error(400));
-
-    // malicious path, forbidden
-    if (0 != path.indexOf(root)) return next(utils.error(403));
-
-    // check if we have a directory
-    fs.stat(path, function(err, stat){
-      if (err) return 'ENOENT' == err.code
-        ? next()
-        : next(err);
-
-      if (!stat.isDirectory()) return next();
-
-      // fetch files
-      fs.readdir(path, function(err, files){
-        if (err) return next(err);
-        if (!hidden) files = removeHidden(files);
-        if (filter) files = files.filter(filter);
-        files.sort();
-
-        // content-negotiation
-        var type = new Negotiator(req).preferredMediaType(mediaTypes);
-
-        // not acceptable
-        if (!type) return next(utils.error(406));
-        exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template);
-      });
-    });
-  };
-};
-
-/**
- * Respond with text/html.
- */
-
-exports.html = function(req, res, files, next, dir, showUp, icons, path, view, template){
-  fs.readFile(template, 'utf8', function(err, str){
-    if (err) return next(err);
-    fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
-      if (err) return next(err);
-      stat(path, files, function(err, stats){
-        if (err) return next(err);
-        files = files.map(function(file, i){ return { name: file, stat: stats[i] }; });
-        files.sort(fileSort);
-        if (showUp) files.unshift({ name: '..' });
-        str = str
-          .replace('{style}', style.concat(iconStyle(files, icons)))
-          .replace('{files}', html(files, dir, icons, view))
-          .replace('{directory}', dir)
-          .replace('{linked-path}', htmlPath(dir));
-        res.setHeader('Content-Type', 'text/html');
-        res.setHeader('Content-Length', str.length);
-        res.end(str);
-      });
-    });
-  });
-};
-
-/**
- * Respond with application/json.
- */
-
-exports.json = function(req, res, files){
-  files = JSON.stringify(files);
-  res.setHeader('Content-Type', 'application/json');
-  res.setHeader('Content-Length', files.length);
-  res.end(files);
-};
-
-/**
- * Respond with text/plain.
- */
-
-exports.plain = function(req, res, files){
-  files = files.join('\n') + '\n';
-  res.setHeader('Content-Type', 'text/plain');
-  res.setHeader('Content-Length', files.length);
-  res.end(files);
-};
-
-/**
- * Sort function for with directories first.
- */
-
-function fileSort(a, b) {
-  return Number(b.stat && b.stat.isDirectory()) - Number(a.stat && a.stat.isDirectory()) ||
-    String(a.name).toLocaleLowerCase().localeCompare(String(b.name).toLocaleLowerCase());
-}
-
-/**
- * Map html `dir`, returning a linked path.
- */
-
-function htmlPath(dir) {
-  var curr = [];
-  return dir.split('/').map(function(part){
-    curr.push(encodeURIComponent(part));
-    return part ? '<a href="' + curr.join('/') + '">' + part + '</a>' : '';
-  }).join(' / ');
-}
-
-/**
- * Load icon images, return css string.
- */
-
-function iconStyle (files, useIcons) {
-  if (!useIcons) return '';
-  var data = {};
-  var views = { tiles: [], details: [], mobile: [] };
-
-  for (var i=0; i < files.length; i++) {
-    var file = files[i];
-    if (file.name == '..') continue;
-
-    var isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
-    var icon = isDir ? icons.folder : icons[extname(file.name)] || icons.default;
-
-    var ext = extname(file.name);
-    ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
-
-    if (data[icon]) continue;
-    data[icon] = ext + ' .name{background-image: url(data:image/png;base64,' + load(icon)+');}';
-    views.tiles.push('.view-tiles ' + data[icon]);
-  	views.details.push('.view-details ' + data[icon]);
-  	views.mobile.push('#files ' + data[icon]);
-  }
-
-  var style = views.tiles.join('\n')
-    + '\n'+views.details.join('\n')
-    + '\n@media (max-width: 768px) {\n\t'
-    + views.mobile.join('\n\t')
-    + '\n}';
-  return style;
-}
-
-/**
- * Map html `files`, returning an html unordered list.
- */
-
-function html(files, dir, useIcons, view) {
-  	return '<ul id="files" class="view-'+view+'">'
-    + (view == 'details' ? (
-      '<li class="header">'
-      + '<span class="name">Name</span>'
-      + '<span class="size">Size</span>'
-      + '<span class="date">Modified</span>'
-      + '</li>') : '')
-    + files.map(function(file){
-    var isDir
-      , classes = []
-      , path = dir.split('/').map(function (c) { return encodeURIComponent(c); });
-
-    if (useIcons) {
-      var ext = extname(file.name);
-      isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
-      ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
-      classes.push('icon');
-      classes.push(ext.replace('.',''));
-    }
-
-    path.push(encodeURIComponent(file.name));
-
-    var date = file.name == '..' ? ''
-      : file.stat.mtime.toDateString()+' '+file.stat.mtime.toLocaleTimeString();
-    var size = file.name == '..' ? '' : file.stat.size;
-
-    return '<li><a href="'
-      + utils.normalizeSlashes(normalize(path.join('/')))
-      + '" class="'
-      + classes.join(' ') + '"'
-      + ' title="' + file.name + '">'
-      + '<span class="name">'+file.name+'</span>'
-      + '<span class="size">'+size+'</span>'
-      + '<span class="date">'+date+'</span>'
-      + '</a></li>';
-
-  }).join('\n') + '</ul>';
-}
-
-/**
- * Load and cache the given `icon`.
- *
- * @param {String} icon
- * @return {String}
- * @api private
- */
-
-function load(icon) {
-  if (cache[icon]) return cache[icon];
-  return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
-}
-
-/**
- * Filter "hidden" `files`, aka files
- * beginning with a `.`.
- *
- * @param {Array} files
- * @return {Array}
- * @api private
- */
-
-function removeHidden(files) {
-  return files.filter(function(file){
-    return '.' != file[0];
-  });
-}
-
-/**
- * Stat all files and return array of stat
- * in same order.
- */
-
-function stat(dir, files, cb) {
-  var batch = new Batch();
-
-  batch.concurrency(10);
-
-  files.forEach(function(file, i){
-    batch.push(function(done){
-      fs.stat(join(dir, file), done);
-    });
-  });
-
-  batch.end(cb);
-}
-
-/**
- * Icon map.
- */
-
-var icons = {
-    '.js': 'page_white_code_red.png'
-  , '.c': 'page_white_c.png'
-  , '.h': 'page_white_h.png'
-  , '.cc': 'page_white_cplusplus.png'
-  , '.php': 'page_white_php.png'
-  , '.rb': 'page_white_ruby.png'
-  , '.cpp': 'page_white_cplusplus.png'
-  , '.swf': 'page_white_flash.png'
-  , '.pdf': 'page_white_acrobat.png'
-  , 'folder': 'folder.png'
-  , 'default': 'page_white.png'
-};
+module.exports = require('serve-index');
diff --git a/lib/public/directory.html b/lib/public/directory.html
deleted file mode 100644
index 8ed8b4a..0000000
--- a/lib/public/directory.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset='utf-8'> 
-    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
-    <title>listing directory {directory}</title>
-    <style>{style}</style>
-    <script>
-      function $(id){
-        var el = 'string' == typeof id
-          ? document.getElementById(id)
-          : id;
-
-        el.on = function(event, fn){
-          if ('content loaded' == event) {
-            event = window.attachEvent ? "load" : "DOMContentLoaded";
-          }
-          el.addEventListener
-            ? el.addEventListener(event, fn, false)
-            : el.attachEvent("on" + event, fn);
-        };
-
-        el.all = function(selector){
-          return $(el.querySelectorAll(selector));
-        };
-
-        el.each = function(fn){
-          for (var i = 0, len = el.length; i < len; ++i) {
-            fn($(el[i]), i);
-          }
-        };
-
-        el.getClasses = function(){
-          return this.getAttribute('class').split(/\s+/);
-        };
-
-        el.addClass = function(name){
-          var classes = this.getAttribute('class');
-          el.setAttribute('class', classes
-            ? classes + ' ' + name
-            : name);
-        };
-
-        el.removeClass = function(name){
-          var classes = this.getClasses().filter(function(curr){
-            return curr != name;
-          });
-          this.setAttribute('class', classes.join(' '));
-        };
-
-        return el;
-      }
-
-      function search() {
-        var str = $('search').value
-          , links = $('files').all('a');
-
-        links.each(function(link){
-          var text = link.textContent;
-
-          if ('..' == text) return;
-          if (str.length && ~text.indexOf(str)) {
-            link.addClass('highlight');
-          } else {
-            link.removeClass('highlight');
-          }
-        });
-      }
-
-      $(window).on('content loaded', function(){
-        $('search').on('keyup', search);
-      });
-    </script>
-  </head>
-  <body class="directory">
-    <input id="search" type="text" placeholder="Search" autocomplete="off" />
-    <div id="wrapper">
-      <h1>{linked-path}</h1>
-      {files}
-    </div>
-  </body>
-</html>
\ No newline at end of file
diff --git a/lib/public/favicon.ico b/lib/public/favicon.ico
deleted file mode 100644
index 895fc96..0000000
Binary files a/lib/public/favicon.ico and /dev/null differ
diff --git a/lib/public/icons/folder.png b/lib/public/icons/folder.png
deleted file mode 100644
index 698f3d3..0000000
Binary files a/lib/public/icons/folder.png and /dev/null differ
diff --git a/lib/public/icons/page.png b/lib/public/icons/page.png
deleted file mode 100644
index 03ddd79..0000000
Binary files a/lib/public/icons/page.png and /dev/null differ
diff --git a/lib/public/icons/page_add.png b/lib/public/icons/page_add.png
deleted file mode 100644
index d5bfa07..0000000
Binary files a/lib/public/icons/page_add.png and /dev/null differ
diff --git a/lib/public/icons/page_attach.png b/lib/public/icons/page_attach.png
deleted file mode 100644
index 89ee2da..0000000
Binary files a/lib/public/icons/page_attach.png and /dev/null differ
diff --git a/lib/public/icons/page_code.png b/lib/public/icons/page_code.png
deleted file mode 100644
index f7ea904..0000000
Binary files a/lib/public/icons/page_code.png and /dev/null differ
diff --git a/lib/public/icons/page_copy.png b/lib/public/icons/page_copy.png
deleted file mode 100644
index 195dc6d..0000000
Binary files a/lib/public/icons/page_copy.png and /dev/null differ
diff --git a/lib/public/icons/page_delete.png b/lib/public/icons/page_delete.png
deleted file mode 100644
index 3141467..0000000
Binary files a/lib/public/icons/page_delete.png and /dev/null differ
diff --git a/lib/public/icons/page_edit.png b/lib/public/icons/page_edit.png
deleted file mode 100644
index 046811e..0000000
Binary files a/lib/public/icons/page_edit.png and /dev/null differ
diff --git a/lib/public/icons/page_error.png b/lib/public/icons/page_error.png
deleted file mode 100644
index f07f449..0000000
Binary files a/lib/public/icons/page_error.png and /dev/null differ
diff --git a/lib/public/icons/page_excel.png b/lib/public/icons/page_excel.png
deleted file mode 100644
index eb6158e..0000000
Binary files a/lib/public/icons/page_excel.png and /dev/null differ
diff --git a/lib/public/icons/page_find.png b/lib/public/icons/page_find.png
deleted file mode 100644
index 2f19388..0000000
Binary files a/lib/public/icons/page_find.png and /dev/null differ
diff --git a/lib/public/icons/page_gear.png b/lib/public/icons/page_gear.png
deleted file mode 100644
index 8e83281..0000000
Binary files a/lib/public/icons/page_gear.png and /dev/null differ
diff --git a/lib/public/icons/page_go.png b/lib/public/icons/page_go.png
deleted file mode 100644
index 80fe1ed..0000000
Binary files a/lib/public/icons/page_go.png and /dev/null differ
diff --git a/lib/public/icons/page_green.png b/lib/public/icons/page_green.png
deleted file mode 100644
index de8e003..0000000
Binary files a/lib/public/icons/page_green.png and /dev/null differ
diff --git a/lib/public/icons/page_key.png b/lib/public/icons/page_key.png
deleted file mode 100644
index d6626cb..0000000
Binary files a/lib/public/icons/page_key.png and /dev/null differ
diff --git a/lib/public/icons/page_lightning.png b/lib/public/icons/page_lightning.png
deleted file mode 100644
index 7e56870..0000000
Binary files a/lib/public/icons/page_lightning.png and /dev/null differ
diff --git a/lib/public/icons/page_link.png b/lib/public/icons/page_link.png
deleted file mode 100644
index 312eab0..0000000
Binary files a/lib/public/icons/page_link.png and /dev/null differ
diff --git a/lib/public/icons/page_paintbrush.png b/lib/public/icons/page_paintbrush.png
deleted file mode 100644
index 246a2f0..0000000
Binary files a/lib/public/icons/page_paintbrush.png and /dev/null differ
diff --git a/lib/public/icons/page_paste.png b/lib/public/icons/page_paste.png
deleted file mode 100644
index 968f073..0000000
Binary files a/lib/public/icons/page_paste.png and /dev/null differ
diff --git a/lib/public/icons/page_red.png b/lib/public/icons/page_red.png
deleted file mode 100644
index 0b18247..0000000
Binary files a/lib/public/icons/page_red.png and /dev/null differ
diff --git a/lib/public/icons/page_refresh.png b/lib/public/icons/page_refresh.png
deleted file mode 100644
index cf347c7..0000000
Binary files a/lib/public/icons/page_refresh.png and /dev/null differ
diff --git a/lib/public/icons/page_save.png b/lib/public/icons/page_save.png
deleted file mode 100644
index caea546..0000000
Binary files a/lib/public/icons/page_save.png and /dev/null differ
diff --git a/lib/public/icons/page_white.png b/lib/public/icons/page_white.png
deleted file mode 100644
index 8b8b1ca..0000000
Binary files a/lib/public/icons/page_white.png and /dev/null differ
diff --git a/lib/public/icons/page_white_acrobat.png b/lib/public/icons/page_white_acrobat.png
deleted file mode 100644
index 8f8095e..0000000
Binary files a/lib/public/icons/page_white_acrobat.png and /dev/null differ
diff --git a/lib/public/icons/page_white_actionscript.png b/lib/public/icons/page_white_actionscript.png
deleted file mode 100644
index 159b240..0000000
Binary files a/lib/public/icons/page_white_actionscript.png and /dev/null differ
diff --git a/lib/public/icons/page_white_add.png b/lib/public/icons/page_white_add.png
deleted file mode 100644
index aa23dde..0000000
Binary files a/lib/public/icons/page_white_add.png and /dev/null differ
diff --git a/lib/public/icons/page_white_c.png b/lib/public/icons/page_white_c.png
deleted file mode 100644
index 34a05cc..0000000
Binary files a/lib/public/icons/page_white_c.png and /dev/null differ
diff --git a/lib/public/icons/page_white_camera.png b/lib/public/icons/page_white_camera.png
deleted file mode 100644
index f501a59..0000000
Binary files a/lib/public/icons/page_white_camera.png and /dev/null differ
diff --git a/lib/public/icons/page_white_cd.png b/lib/public/icons/page_white_cd.png
deleted file mode 100644
index 848bdaf..0000000
Binary files a/lib/public/icons/page_white_cd.png and /dev/null differ
diff --git a/lib/public/icons/page_white_code.png b/lib/public/icons/page_white_code.png
deleted file mode 100644
index 0c76bd1..0000000
Binary files a/lib/public/icons/page_white_code.png and /dev/null differ
diff --git a/lib/public/icons/page_white_code_red.png b/lib/public/icons/page_white_code_red.png
deleted file mode 100644
index 87a6914..0000000
Binary files a/lib/public/icons/page_white_code_red.png and /dev/null differ
diff --git a/lib/public/icons/page_white_coldfusion.png b/lib/public/icons/page_white_coldfusion.png
deleted file mode 100644
index c66011f..0000000
Binary files a/lib/public/icons/page_white_coldfusion.png and /dev/null differ
diff --git a/lib/public/icons/page_white_compressed.png b/lib/public/icons/page_white_compressed.png
deleted file mode 100644
index 2b6b100..0000000
Binary files a/lib/public/icons/page_white_compressed.png and /dev/null differ
diff --git a/lib/public/icons/page_white_copy.png b/lib/public/icons/page_white_copy.png
deleted file mode 100644
index a9f31a2..0000000
Binary files a/lib/public/icons/page_white_copy.png and /dev/null differ
diff --git a/lib/public/icons/page_white_cplusplus.png b/lib/public/icons/page_white_cplusplus.png
deleted file mode 100644
index a87cf84..0000000
Binary files a/lib/public/icons/page_white_cplusplus.png and /dev/null differ
diff --git a/lib/public/icons/page_white_csharp.png b/lib/public/icons/page_white_csharp.png
deleted file mode 100644
index ffb8fc9..0000000
Binary files a/lib/public/icons/page_white_csharp.png and /dev/null differ
diff --git a/lib/public/icons/page_white_cup.png b/lib/public/icons/page_white_cup.png
deleted file mode 100644
index 0a7d6f4..0000000
Binary files a/lib/public/icons/page_white_cup.png and /dev/null differ
diff --git a/lib/public/icons/page_white_database.png b/lib/public/icons/page_white_database.png
deleted file mode 100644
index bddba1f..0000000
Binary files a/lib/public/icons/page_white_database.png and /dev/null differ
diff --git a/lib/public/icons/page_white_delete.png b/lib/public/icons/page_white_delete.png
deleted file mode 100644
index af1ecaf..0000000
Binary files a/lib/public/icons/page_white_delete.png and /dev/null differ
diff --git a/lib/public/icons/page_white_dvd.png b/lib/public/icons/page_white_dvd.png
deleted file mode 100644
index 4cc537a..0000000
Binary files a/lib/public/icons/page_white_dvd.png and /dev/null differ
diff --git a/lib/public/icons/page_white_edit.png b/lib/public/icons/page_white_edit.png
deleted file mode 100644
index b93e776..0000000
Binary files a/lib/public/icons/page_white_edit.png and /dev/null differ
diff --git a/lib/public/icons/page_white_error.png b/lib/public/icons/page_white_error.png
deleted file mode 100644
index 9fc5a0a..0000000
Binary files a/lib/public/icons/page_white_error.png and /dev/null differ
diff --git a/lib/public/icons/page_white_excel.png b/lib/public/icons/page_white_excel.png
deleted file mode 100644
index b977d7e..0000000
Binary files a/lib/public/icons/page_white_excel.png and /dev/null differ
diff --git a/lib/public/icons/page_white_find.png b/lib/public/icons/page_white_find.png
deleted file mode 100644
index 5818436..0000000
Binary files a/lib/public/icons/page_white_find.png and /dev/null differ
diff --git a/lib/public/icons/page_white_flash.png b/lib/public/icons/page_white_flash.png
deleted file mode 100644
index 5769120..0000000
Binary files a/lib/public/icons/page_white_flash.png and /dev/null differ
diff --git a/lib/public/icons/page_white_freehand.png b/lib/public/icons/page_white_freehand.png
deleted file mode 100644
index 8d719df..0000000
Binary files a/lib/public/icons/page_white_freehand.png and /dev/null differ
diff --git a/lib/public/icons/page_white_gear.png b/lib/public/icons/page_white_gear.png
deleted file mode 100644
index 106f5aa..0000000
Binary files a/lib/public/icons/page_white_gear.png and /dev/null differ
diff --git a/lib/public/icons/page_white_get.png b/lib/public/icons/page_white_get.png
deleted file mode 100644
index e4a1ecb..0000000
Binary files a/lib/public/icons/page_white_get.png and /dev/null differ
diff --git a/lib/public/icons/page_white_go.png b/lib/public/icons/page_white_go.png
deleted file mode 100644
index 7e62a92..0000000
Binary files a/lib/public/icons/page_white_go.png and /dev/null differ
diff --git a/lib/public/icons/page_white_h.png b/lib/public/icons/page_white_h.png
deleted file mode 100644
index e902abb..0000000
Binary files a/lib/public/icons/page_white_h.png and /dev/null differ
diff --git a/lib/public/icons/page_white_horizontal.png b/lib/public/icons/page_white_horizontal.png
deleted file mode 100644
index 1d2d0a4..0000000
Binary files a/lib/public/icons/page_white_horizontal.png and /dev/null differ
diff --git a/lib/public/icons/page_white_key.png b/lib/public/icons/page_white_key.png
deleted file mode 100644
index d616484..0000000
Binary files a/lib/public/icons/page_white_key.png and /dev/null differ
diff --git a/lib/public/icons/page_white_lightning.png b/lib/public/icons/page_white_lightning.png
deleted file mode 100644
index 7215d1e..0000000
Binary files a/lib/public/icons/page_white_lightning.png and /dev/null differ
diff --git a/lib/public/icons/page_white_link.png b/lib/public/icons/page_white_link.png
deleted file mode 100644
index bf7bd1c..0000000
Binary files a/lib/public/icons/page_white_link.png and /dev/null differ
diff --git a/lib/public/icons/page_white_magnify.png b/lib/public/icons/page_white_magnify.png
deleted file mode 100644
index f6b74cc..0000000
Binary files a/lib/public/icons/page_white_magnify.png and /dev/null differ
diff --git a/lib/public/icons/page_white_medal.png b/lib/public/icons/page_white_medal.png
deleted file mode 100644
index d3fffb6..0000000
Binary files a/lib/public/icons/page_white_medal.png and /dev/null differ
diff --git a/lib/public/icons/page_white_office.png b/lib/public/icons/page_white_office.png
deleted file mode 100644
index a65bcb3..0000000
Binary files a/lib/public/icons/page_white_office.png and /dev/null differ
diff --git a/lib/public/icons/page_white_paint.png b/lib/public/icons/page_white_paint.png
deleted file mode 100644
index 23a37b8..0000000
Binary files a/lib/public/icons/page_white_paint.png and /dev/null differ
diff --git a/lib/public/icons/page_white_paintbrush.png b/lib/public/icons/page_white_paintbrush.png
deleted file mode 100644
index f907e44..0000000
Binary files a/lib/public/icons/page_white_paintbrush.png and /dev/null differ
diff --git a/lib/public/icons/page_white_paste.png b/lib/public/icons/page_white_paste.png
deleted file mode 100644
index 5b2cbb3..0000000
Binary files a/lib/public/icons/page_white_paste.png and /dev/null differ
diff --git a/lib/public/icons/page_white_php.png b/lib/public/icons/page_white_php.png
deleted file mode 100644
index 7868a25..0000000
Binary files a/lib/public/icons/page_white_php.png and /dev/null differ
diff --git a/lib/public/icons/page_white_picture.png b/lib/public/icons/page_white_picture.png
deleted file mode 100644
index 134b669..0000000
Binary files a/lib/public/icons/page_white_picture.png and /dev/null differ
diff --git a/lib/public/icons/page_white_powerpoint.png b/lib/public/icons/page_white_powerpoint.png
deleted file mode 100644
index c4eff03..0000000
Binary files a/lib/public/icons/page_white_powerpoint.png and /dev/null differ
diff --git a/lib/public/icons/page_white_put.png b/lib/public/icons/page_white_put.png
deleted file mode 100644
index 884ffd6..0000000
Binary files a/lib/public/icons/page_white_put.png and /dev/null differ
diff --git a/lib/public/icons/page_white_ruby.png b/lib/public/icons/page_white_ruby.png
deleted file mode 100644
index f59b7c4..0000000
Binary files a/lib/public/icons/page_white_ruby.png and /dev/null differ
diff --git a/lib/public/icons/page_white_stack.png b/lib/public/icons/page_white_stack.png
deleted file mode 100644
index 44084ad..0000000
Binary files a/lib/public/icons/page_white_stack.png and /dev/null differ
diff --git a/lib/public/icons/page_white_star.png b/lib/public/icons/page_white_star.png
deleted file mode 100644
index 3a1441c..0000000
Binary files a/lib/public/icons/page_white_star.png and /dev/null differ
diff --git a/lib/public/icons/page_white_swoosh.png b/lib/public/icons/page_white_swoosh.png
deleted file mode 100644
index e770829..0000000
Binary files a/lib/public/icons/page_white_swoosh.png and /dev/null differ
diff --git a/lib/public/icons/page_white_text.png b/lib/public/icons/page_white_text.png
deleted file mode 100644
index 813f712..0000000
Binary files a/lib/public/icons/page_white_text.png and /dev/null differ
diff --git a/lib/public/icons/page_white_text_width.png b/lib/public/icons/page_white_text_width.png
deleted file mode 100644
index d9cf132..0000000
Binary files a/lib/public/icons/page_white_text_width.png and /dev/null differ
diff --git a/lib/public/icons/page_white_tux.png b/lib/public/icons/page_white_tux.png
deleted file mode 100644
index 52699bf..0000000
Binary files a/lib/public/icons/page_white_tux.png and /dev/null differ
diff --git a/lib/public/icons/page_white_vector.png b/lib/public/icons/page_white_vector.png
deleted file mode 100644
index 4a05955..0000000
Binary files a/lib/public/icons/page_white_vector.png and /dev/null differ
diff --git a/lib/public/icons/page_white_visualstudio.png b/lib/public/icons/page_white_visualstudio.png
deleted file mode 100644
index a0a433d..0000000
Binary files a/lib/public/icons/page_white_visualstudio.png and /dev/null differ
diff --git a/lib/public/icons/page_white_width.png b/lib/public/icons/page_white_width.png
deleted file mode 100644
index 1eb8809..0000000
Binary files a/lib/public/icons/page_white_width.png and /dev/null differ
diff --git a/lib/public/icons/page_white_word.png b/lib/public/icons/page_white_word.png
deleted file mode 100644
index ae8ecbf..0000000
Binary files a/lib/public/icons/page_white_word.png and /dev/null differ
diff --git a/lib/public/icons/page_white_world.png b/lib/public/icons/page_white_world.png
deleted file mode 100644
index 6ed2490..0000000
Binary files a/lib/public/icons/page_white_world.png and /dev/null differ
diff --git a/lib/public/icons/page_white_wrench.png b/lib/public/icons/page_white_wrench.png
deleted file mode 100644
index fecadd0..0000000
Binary files a/lib/public/icons/page_white_wrench.png and /dev/null differ
diff --git a/lib/public/icons/page_white_zip.png b/lib/public/icons/page_white_zip.png
deleted file mode 100644
index fd4bbcc..0000000
Binary files a/lib/public/icons/page_white_zip.png and /dev/null differ
diff --git a/lib/public/icons/page_word.png b/lib/public/icons/page_word.png
deleted file mode 100644
index 834cdfa..0000000
Binary files a/lib/public/icons/page_word.png and /dev/null differ
diff --git a/lib/public/icons/page_world.png b/lib/public/icons/page_world.png
deleted file mode 100644
index b8895dd..0000000
Binary files a/lib/public/icons/page_world.png and /dev/null differ
diff --git a/lib/public/style.css b/lib/public/style.css
deleted file mode 100644
index 0709908..0000000
--- a/lib/public/style.css
+++ /dev/null
@@ -1,257 +0,0 @@
-* {
-  margin: 0;
-  padding: 0;
-  outline: 0;
-}
-
-body {
-  padding: 80px 100px;
-  font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
-  background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
-  background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
-  background-repeat: no-repeat;
-  color: #555;
-  -webkit-font-smoothing: antialiased;
-}
-h1, h2, h3 {
-  font-size: 22px;
-  color: #343434;
-}
-h1 em, h2 em {
-  padding: 0 5px;
-  font-weight: normal;
-}
-h1 {
-  font-size: 60px;
-}
-h2 {
-  margin-top: 10px;
-}
-h3 {
-  margin: 5px 0 10px 0;
-  padding-bottom: 5px;
-  border-bottom: 1px solid #eee;
-  font-size: 18px;
-}
-ul li {
-  list-style: none;
-}
-ul li:hover {
-  cursor: pointer;
-  color: #2e2e2e;
-}
-ul li .path {
-  padding-left: 5px;
-  font-weight: bold;
-}
-ul li .line {
-  padding-right: 5px;
-  font-style: italic;
-}
-ul li:first-child .path {
-  padding-left: 0;
-}
-p {
-  line-height: 1.5;
-}
-a {
-  color: #555;
-  text-decoration: none;
-}
-a:hover {
-  color: #303030;
-}
-#stacktrace {
-  margin-top: 15px;
-}
-.directory h1 {
-  margin-bottom: 15px;
-  font-size: 18px;
-}
-ul#files {
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-}
-ul#files li {
-  float: left;
-  width: 30%;
-  line-height: 25px;
-  margin: 1px;
-}
-ul#files li a {
-  display: block;
-  height: 25px;
-  border: 1px solid transparent;
-  -webkit-border-radius: 5px;
-  -moz-border-radius: 5px;
-  border-radius: 5px;
-  overflow: hidden;
-  white-space: nowrap;
-}
-ul#files li a:focus,
-ul#files li a:hover {
-  background: rgba(255,255,255,0.65);
-  border: 1px solid #ececec;
-}
-ul#files li a.highlight {
-  -webkit-transition: background .4s ease-in-out;
-  background: #ffff4f;
-  border-color: #E9DC51;
-}
-#search {
-  display: block;
-  position: fixed;
-  top: 20px;
-  right: 20px;
-  width: 90px;
-  -webkit-transition: width ease 0.2s, opacity ease 0.4s;
-  -moz-transition: width ease 0.2s, opacity ease 0.4s;
-  -webkit-border-radius: 32px;
-  -moz-border-radius: 32px;
-  -webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-  -moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-  -webkit-font-smoothing: antialiased;
-  text-align: left;
-  font: 13px "Helvetica Neue", Arial, sans-serif;
-  padding: 4px 10px;
-  border: none;
-  background: transparent;
-  margin-bottom: 0;
-  outline: none;
-  opacity: 0.7;
-  color: #888;
-}
-#search:focus {
-  width: 120px;
-  opacity: 1.0; 
-}
-
-/*views*/
-#files span {
-  display: inline-block;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  text-indent: 10px;
-}
-#files .name {
-  background-repeat: no-repeat;
-}
-#files .icon .name {
-  text-indent: 28px;
-}
-
-/*tiles*/
-.view-tiles .name {
-  width: 100%;
-  background-position: 8px 5px;
-}
-.view-tiles .size,
-.view-tiles .date {
-  display: none;
-}
-
-/*details*/
-ul#files.view-details li {
-  float: none;
-  display: block;
-  width: 90%;
-}
-ul#files.view-details li.header {
-  height: 25px;
-  background: #000;
-  color: #fff;
-  font-weight: bold;
-}
-.view-details .header {
-  border-radius: 5px;
-}
-.view-details .name {
-  width: 60%;
-  background-position: 8px 5px;
-}
-.view-details .size {
-  width: 10%;
-}
-.view-details .date {
-  width: 30%;
-}
-.view-details .size,
-.view-details .date {
-  text-align: right;
-  direction: rtl;
-}
-
-/*mobile*/
-@media (max-width: 768px) {
-  body {
-    font-size: 13px;
-    line-height: 16px;
-    padding: 0;
-  }
-  #search {
-    position: static;
-    width: 100%;
-    font-size: 2em;
-    line-height: 1.8em;
-    text-indent: 10px;
-    border: 0;
-    border-radius: 0;
-    padding: 10px 0;
-    margin: 0;
-  }
-  #search:focus {
-    width: 100%;
-    border: 0;
-    opacity: 1;
-  }
-  .directory h1 {
-    font-size: 2em;
-    line-height: 1.5em;
-    color: #fff;
-    background: #000;
-    padding: 15px 10px;
-    margin: 0;
-  }
-  ul#files {
-    border-top: 1px solid #cacaca;
-  }
-  ul#files li {
-    float: none;
-    width: auto !important;
-    display: block;
-    border-bottom: 1px solid #cacaca;
-    font-size: 2em;
-    line-height: 1.2em;
-    text-indent: 0;
-    margin: 0;
-  }
-  ul#files li:nth-child(odd) {
-    background: #e0e0e0;
-  }
-  ul#files li a {
-    height: auto;
-    border: 0;
-    border-radius: 0;
-    padding: 15px 10px;
-  }
-  ul#files li a:focus,
-  ul#files li a:hover {
-    border: 0;
-  }
-  #files .header,
-  #files .size,
-  #files .date {
-    display: none !important;
-  }
-  #files .name {
-    float: none;
-    display: inline-block;
-    width: 100%;
-    text-indent: 0;
-    background-position: 0 0;
-  }
-  #files .icon .name {
-    text-indent: 41px;
-  }
-}
diff --git a/package.json b/package.json
index 834d3bd..cf0ae53 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,10 @@
   ],
   "repository": "git://github.com/senchalabs/connect.git",
   "author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)",
   "dependencies": {
     "basic-auth-connect": "1.0.0",
-    "batch": "0.5.0",
     "cookie-parser": "1.0.1",
     "cookie-signature": "1.0.3",
     "compression": "1.0.0",
     "connect-timeout": "1.0.0",
     "csurf": "1.0.0",
@@ -23,19 +22,19 @@
     "express-session": "1.0.2",
     "method-override": "1.0.0",
     "morgan": "1.0.0",
     "qs": "0.6.6",
     "response-time": "1.0.0",
+    "serve-index": "1.0.0",
     "static-favicon": "1.0.0",
     "vhost": "1.0.0",
     "send": "0.1.4",
     "bytes": "0.2.1",
     "fresh": "0.2.0",
     "pause": "0.0.1",
     "debug": ">= 0.7.3 < 1",
     "raw-body": "1.1.3",
-    "negotiator": "0.3.0",
     "multiparty": "2.2.0"
   },
   "devDependencies": {
     "should": ">= 2.0.2 < 3",
     "mocha": ">= 1.13.0 < 2",

Vulnerable code:  *  - [directory](directory.html) directory listing middleware
// TODO: arrow key navigation
// TODO: make icons extensible

/**
 * Module dependencies.
 */

var fs = require('fs')
  , parse = require('url').parse
  , utils = require('../utils')
  , path = require('path')
  , normalize = path.normalize
  , sep = path.sep
  , extname = path.extname
  , join = path.join;
var Batch = require('batch');
var Negotiator = require('negotiator');

/*!
 * Icon cache.
 */

var cache = {};

/*!
 * Default template.
 */

var defaultTemplate = join(__dirname, '..', 'public', 'directory.html');

/**
 * Media types and the map for content negotiation.
 */

var mediaTypes = [
  'text/html',
  'text/plain',
  'application/json'
];

var mediaType = {
  'text/html': 'html',
  'text/plain': 'plain',
  'application/json': 'json'
};

 * Serve directory listings with the given `root` path.
 *
 * Options:
 *
 *  - `hidden` display hidden (dot) files. Defaults to false.
 *  - `icons`  display icons. Defaults to false.
 *  - `filter` Apply this filter function to files. Defaults to false.
 *  - `template` Optional path to html template. Defaults to a built-in template.
 *    The following tokens are replaced:
 *      - `{directory}` with the name of the directory.
 *      - `{files}` with the HTML of an unordered list of file links.
 *      - `{linked-path}` with the HTML of a link to the directory.
 *      - `{style}` with the built-in CSS and embedded images.
exports = module.exports = function directory(root, options){
  options = options || {};

  // root required
  if (!root) throw new Error('directory() root path required');
  var hidden = options.hidden
    , icons = options.icons
    , view = options.view || 'tiles'
    , filter = options.filter
    , root = normalize(root + sep)
    , template = options.template || defaultTemplate;

  return function directory(req, res, next) {
    if ('GET' != req.method && 'HEAD' != req.method) return next();

    var url = parse(req.url)
      , dir = decodeURIComponent(url.pathname)
      , path = normalize(join(root, dir))
      , originalUrl = parse(req.originalUrl)
      , originalDir = decodeURIComponent(originalUrl.pathname)
      , showUp = path != root;

    // null byte(s), bad request
    if (~path.indexOf('\0')) return next(utils.error(400));

    // malicious path, forbidden
    if (0 != path.indexOf(root)) return next(utils.error(403));

    // check if we have a directory
    fs.stat(path, function(err, stat){
      if (err) return 'ENOENT' == err.code
        ? next()
        : next(err);

      if (!stat.isDirectory()) return next();

      // fetch files
      fs.readdir(path, function(err, files){
        if (err) return next(err);
        if (!hidden) files = removeHidden(files);
        if (filter) files = files.filter(filter);
        files.sort();

        // content-negotiation
        var type = new Negotiator(req).preferredMediaType(mediaTypes);

        // not acceptable
        if (!type) return next(utils.error(406));
        exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template);
      });
    });
  };
};

/**
 * Respond with text/html.
 */

exports.html = function(req, res, files, next, dir, showUp, icons, path, view, template){
  fs.readFile(template, 'utf8', function(err, str){
    if (err) return next(err);
    fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
      if (err) return next(err);
      stat(path, files, function(err, stats){
        if (err) return next(err);
        files = files.map(function(file, i){ return { name: file, stat: stats[i] }; });
        files.sort(fileSort);
        if (showUp) files.unshift({ name: '..' });
        str = str
          .replace('{style}', style.concat(iconStyle(files, icons)))
          .replace('{files}', html(files, dir, icons, view))
          .replace('{directory}', dir)
          .replace('{linked-path}', htmlPath(dir));
        res.setHeader('Content-Type', 'text/html');
        res.setHeader('Content-Length', str.length);
        res.end(str);
      });
    });
  });
};

/**
 * Respond with application/json.
 */

exports.json = function(req, res, files){
  files = JSON.stringify(files);
  res.setHeader('Content-Type', 'application/json');
  res.setHeader('Content-Length', files.length);
  res.end(files);
};

/**
 * Respond with text/plain.
 */

exports.plain = function(req, res, files){
  files = files.join('\n') + '\n';
  res.setHeader('Content-Type', 'text/plain');
  res.setHeader('Content-Length', files.length);
  res.end(files);
};

/**
 * Sort function for with directories first.
 */

function fileSort(a, b) {
  return Number(b.stat && b.stat.isDirectory()) - Number(a.stat && a.stat.isDirectory()) ||
    String(a.name).toLocaleLowerCase().localeCompare(String(b.name).toLocaleLowerCase());
}

/**
 * Map html `dir`, returning a linked path.
 */

function htmlPath(dir) {
  var curr = [];
  return dir.split('/').map(function(part){
    curr.push(encodeURIComponent(part));
    return part ? '<a href="' + curr.join('/') + '">' + part + '</a>' : '';
  }).join(' / ');
}

/**
 * Load icon images, return css string.
 */

function iconStyle (files, useIcons) {
  if (!useIcons) return '';
  var data = {};
  var views = { tiles: [], details: [], mobile: [] };

  for (var i=0; i < files.length; i++) {
    var file = files[i];
    if (file.name == '..') continue;

    var isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
    var icon = isDir ? icons.folder : icons[extname(file.name)] || icons.default;

    var ext = extname(file.name);
    ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');

    if (data[icon]) continue;
    data[icon] = ext + ' .name{background-image: url(data:image/png;base64,' + load(icon)+');}';
    views.tiles.push('.view-tiles ' + data[icon]);
  	views.details.push('.view-details ' + data[icon]);
  	views.mobile.push('#files ' + data[icon]);
  }

  var style = views.tiles.join('\n')
    + '\n'+views.details.join('\n')
    + '\n@media (max-width: 768px) {\n\t'
    + views.mobile.join('\n\t')
    + '\n}';
  return style;
}

/**
 * Map html `files`, returning an html unordered list.
 */

function html(files, dir, useIcons, view) {
  	return '<ul id="files" class="view-'+view+'">'
    + (view == 'details' ? (
      '<li class="header">'
      + '<span class="name">Name</span>'
      + '<span class="size">Size</span>'
      + '<span class="date">Modified</span>'
      + '</li>') : '')
    + files.map(function(file){
    var isDir
      , classes = []
      , path = dir.split('/').map(function (c) { return encodeURIComponent(c); });

    if (useIcons) {
      var ext = extname(file.name);
      isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
      ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
      classes.push('icon');
      classes.push(ext.replace('.',''));
    }

    path.push(encodeURIComponent(file.name));

    var date = file.name == '..' ? ''
      : file.stat.mtime.toDateString()+' '+file.stat.mtime.toLocaleTimeString();
    var size = file.name == '..' ? '' : file.stat.size;

    return '<li><a href="'
      + utils.normalizeSlashes(normalize(path.join('/')))
      + '" class="'
      + classes.join(' ') + '"'
      + ' title="' + file.name + '">'
      + '<span class="name">'+file.name+'</span>'
      + '<span class="size">'+size+'</span>'
      + '<span class="date">'+date+'</span>'
      + '</a></li>';

  }).join('\n') + '</ul>';
}

/**
 * Load and cache the given `icon`.
 *
 * @param {String} icon
 * @return {String}
 * @api private
 */

function load(icon) {
  if (cache[icon]) return cache[icon];
  return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
}

/**
 * Filter "hidden" `files`, aka files
 * beginning with a `.`.
 *
 * @param {Array} files
 * @return {Array}
 * @api private
 */

function removeHidden(files) {
  return files.filter(function(file){
    return '.' != file[0];
  });
}

/**
 * Stat all files and return array of stat
 * in same order.
 */

function stat(dir, files, cb) {
  var batch = new Batch();

  batch.concurrency(10);

  files.forEach(function(file, i){
    batch.push(function(done){
      fs.stat(join(dir, file), done);
    });
  });

  batch.end(cb);
}

/**
 * Icon map.
 */

var icons = {
    '.js': 'page_white_code_red.png'
  , '.c': 'page_white_c.png'
  , '.h': 'page_white_h.png'
  , '.cc': 'page_white_cplusplus.png'
  , '.php': 'page_white_php.png'
  , '.rb': 'page_white_ruby.png'
  , '.cpp': 'page_white_cplusplus.png'
  , '.swf': 'page_white_flash.png'
  , '.pdf': 'page_white_acrobat.png'
  , 'folder': 'folder.png'
  , 'default': 'page_white.png'
};
<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>listing directory {directory}</title>
    <style>{style}</style>
    <script>
      function $(id){
        var el = 'string' == typeof id
          ? document.getElementById(id)
          : id;

        el.on = function(event, fn){
          if ('content loaded' == event) {
            event = window.attachEvent ? "load" : "DOMContentLoaded";
          }
          el.addEventListener
            ? el.addEventListener(event, fn, false)
            : el.attachEvent("on" + event, fn);
        };

        el.all = function(selector){
          return $(el.querySelectorAll(selector));
        };

        el.each = function(fn){
          for (var i = 0, len = el.length; i < len; ++i) {
            fn($(el[i]), i);
          }
        };

        el.getClasses = function(){
          return this.getAttribute('class').split(/\s+/);
        };

        el.addClass = function(name){
          var classes = this.getAttribute('class');
          el.setAttribute('class', classes
            ? classes + ' ' + name
            : name);
        };

        el.removeClass = function(name){
          var classes = this.getClasses().filter(function(curr){
            return curr != name;
          });
          this.setAttribute('class', classes.join(' '));
        };

        return el;
      }

      function search() {
        var str = $('search').value
          , links = $('files').all('a');

        links.each(function(link){
          var text = link.textContent;

          if ('..' == text) return;
          if (str.length && ~text.indexOf(str)) {
            link.addClass('highlight');
          } else {
            link.removeClass('highlight');
          }
        });
      }

      $(window).on('content loaded', function(){
        $('search').on('keyup', search);
      });
    </script>
  </head>
  <body class="directory">
    <input id="search" type="text" placeholder="Search" autocomplete="off" />
    <div id="wrapper">
      <h1>{linked-path}</h1>
      {files}
    </div>
  </body>
</html>
* {
  margin: 0;
  padding: 0;
  outline: 0;
}

body {
  padding: 80px 100px;
  font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
  background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
  background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
  background-repeat: no-repeat;
  color: #555;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
  font-size: 22px;
  color: #343434;
}
h1 em, h2 em {
  padding: 0 5px;
  font-weight: normal;
}
h1 {
  font-size: 60px;
}
h2 {
  margin-top: 10px;
}
h3 {
  margin: 5px 0 10px 0;
  padding-bottom: 5px;
  border-bottom: 1px solid #eee;
  font-size: 18px;
}
ul li {
  list-style: none;
}
ul li:hover {
  cursor: pointer;
  color: #2e2e2e;
}
ul li .path {
  padding-left: 5px;
  font-weight: bold;
}
ul li .line {
  padding-right: 5px;
  font-style: italic;
}
ul li:first-child .path {
  padding-left: 0;
}
p {
  line-height: 1.5;
}
a {
  color: #555;
  text-decoration: none;
}
a:hover {
  color: #303030;
}
#stacktrace {
  margin-top: 15px;
}
.directory h1 {
  margin-bottom: 15px;
  font-size: 18px;
}
ul#files {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
ul#files li {
  float: left;
  width: 30%;
  line-height: 25px;
  margin: 1px;
}
ul#files li a {
  display: block;
  height: 25px;
  border: 1px solid transparent;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
  overflow: hidden;
  white-space: nowrap;
}
ul#files li a:focus,
ul#files li a:hover {
  background: rgba(255,255,255,0.65);
  border: 1px solid #ececec;
}
ul#files li a.highlight {
  -webkit-transition: background .4s ease-in-out;
  background: #ffff4f;
  border-color: #E9DC51;
}
#search {
  display: block;
  position: fixed;
  top: 20px;
  right: 20px;
  width: 90px;
  -webkit-transition: width ease 0.2s, opacity ease 0.4s;
  -moz-transition: width ease 0.2s, opacity ease 0.4s;
  -webkit-border-radius: 32px;
  -moz-border-radius: 32px;
  -webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
  -moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
  -webkit-font-smoothing: antialiased;
  text-align: left;
  font: 13px "Helvetica Neue", Arial, sans-serif;
  padding: 4px 10px;
  border: none;
  background: transparent;
  margin-bottom: 0;
  outline: none;
  opacity: 0.7;
  color: #888;
}
#search:focus {
  width: 120px;
  opacity: 1.0; 
}

/*views*/
#files span {
  display: inline-block;
  overflow: hidden;
  text-overflow: ellipsis;
  text-indent: 10px;
}
#files .name {
  background-repeat: no-repeat;
}
#files .icon .name {
  text-indent: 28px;
}

/*tiles*/
.view-tiles .name {
  width: 100%;
  background-position: 8px 5px;
}
.view-tiles .size,
.view-tiles .date {
  display: none;
}

/*details*/
ul#files.view-details li {
  float: none;
  display: block;
  width: 90%;
}
ul#files.view-details li.header {
  height: 25px;
  background: #000;
  color: #fff;
  font-weight: bold;
}
.view-details .header {
  border-radius: 5px;
}
.view-details .name {
  width: 60%;
  background-position: 8px 5px;
}
.view-details .size {
  width: 10%;
}
.view-details .date {
  width: 30%;
}
.view-details .size,
.view-details .date {
  text-align: right;
  direction: rtl;
}

/*mobile*/
@media (max-width: 768px) {
  body {
    font-size: 13px;
    line-height: 16px;
    padding: 0;
  }
  #search {
    position: static;
    width: 100%;
    font-size: 2em;
    line-height: 1.8em;
    text-indent: 10px;
    border: 0;
    border-radius: 0;
    padding: 10px 0;
    margin: 0;
  }
  #search:focus {
    width: 100%;
    border: 0;
    opacity: 1;
  }
  .directory h1 {
    font-size: 2em;
    line-height: 1.5em;
    color: #fff;
    background: #000;
    padding: 15px 10px;
    margin: 0;
  }
  ul#files {
    border-top: 1px solid #cacaca;
  }
  ul#files li {
    float: none;
    width: auto !important;
    display: block;
    border-bottom: 1px solid #cacaca;
    font-size: 2em;
    line-height: 1.2em;
    text-indent: 0;
    margin: 0;
  }
  ul#files li:nth-child(odd) {
    background: #e0e0e0;
  }
  ul#files li a {
    height: auto;
    border: 0;
    border-radius: 0;
    padding: 15px 10px;
  }
  ul#files li a:focus,
  ul#files li a:hover {
    border: 0;
  }
  #files .header,
  #files .size,
  #files .date {
    display: none !important;
  }
  #files .name {
    float: none;
    display: inline-block;
    width: 100%;
    text-indent: 0;
    background-position: 0 0;
  }
  #files .icon .name {
    text-indent: 41px;
  }
}
    "batch": "0.5.0",
    "negotiator": "0.3.0",
Fixed code:  * directory: use serve-index
 *  - [directory](https://github.com/expressjs/serve-index) directory listing middleware
 * See [serve-index](https://github.com/expressjs/serve-index)
module.exports = require('serve-index');
    "serve-index": "1.0.0",