Prettify
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
const BlacklistAPI = require('../BlacklistAPI')
|
||||
const BlacklistAPI = require("../BlacklistAPI")
|
||||
|
||||
function checkBlacklist(req, res, next) {
|
||||
BlacklistAPI.includesPackage(req.packageName).then(
|
||||
@ -7,7 +7,7 @@ function checkBlacklist(req, res, next) {
|
||||
if (blacklisted) {
|
||||
res
|
||||
.status(403)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Package "${req.packageName}" is blacklisted`)
|
||||
} else {
|
||||
next()
|
||||
@ -17,7 +17,7 @@ function checkBlacklist(req, res, next) {
|
||||
console.error(error)
|
||||
|
||||
res.status(500).send({
|
||||
error: 'Unable to fetch the blacklist'
|
||||
error: "Unable to fetch the blacklist"
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
const React = require('react')
|
||||
const prettyBytes = require('pretty-bytes')
|
||||
const getFileContentType = require('../utils/getFileContentType')
|
||||
const React = require("react")
|
||||
const prettyBytes = require("pretty-bytes")
|
||||
const getFileContentType = require("../utils/getFileContentType")
|
||||
|
||||
const e = React.createElement
|
||||
|
||||
@ -9,46 +9,46 @@ const formatTime = time => new Date(time).toISOString()
|
||||
const DirectoryListing = ({ dir, entries }) => {
|
||||
const rows = entries.map(({ file, stats }, index) => {
|
||||
const isDir = stats.isDirectory()
|
||||
const href = file + (isDir ? '/' : '')
|
||||
const href = file + (isDir ? "/" : "")
|
||||
|
||||
return e(
|
||||
'tr',
|
||||
{ key: file, className: index % 2 ? 'odd' : 'even' },
|
||||
e('td', null, e('a', { title: file, href }, file)),
|
||||
e('td', null, isDir ? '-' : getFileContentType(file)),
|
||||
e('td', null, isDir ? '-' : prettyBytes(stats.size)),
|
||||
e('td', null, isDir ? '-' : formatTime(stats.mtime))
|
||||
"tr",
|
||||
{ key: file, className: index % 2 ? "odd" : "even" },
|
||||
e("td", null, e("a", { title: file, href }, file)),
|
||||
e("td", null, isDir ? "-" : getFileContentType(file)),
|
||||
e("td", null, isDir ? "-" : prettyBytes(stats.size)),
|
||||
e("td", null, isDir ? "-" : formatTime(stats.mtime))
|
||||
)
|
||||
})
|
||||
|
||||
if (dir !== '/')
|
||||
if (dir !== "/")
|
||||
rows.unshift(
|
||||
e(
|
||||
'tr',
|
||||
{ key: '..', className: 'odd' },
|
||||
e('td', null, e('a', { title: 'Parent directory', href: '../' }, '..')),
|
||||
e('td', null, '-'),
|
||||
e('td', null, '-'),
|
||||
e('td', null, '-')
|
||||
"tr",
|
||||
{ key: "..", className: "odd" },
|
||||
e("td", null, e("a", { title: "Parent directory", href: "../" }, "..")),
|
||||
e("td", null, "-"),
|
||||
e("td", null, "-"),
|
||||
e("td", null, "-")
|
||||
)
|
||||
)
|
||||
|
||||
return e(
|
||||
'table',
|
||||
"table",
|
||||
null,
|
||||
e(
|
||||
'thead',
|
||||
"thead",
|
||||
null,
|
||||
e(
|
||||
'tr',
|
||||
"tr",
|
||||
null,
|
||||
e('th', null, 'Name'),
|
||||
e('th', null, 'Type'),
|
||||
e('th', null, 'Size'),
|
||||
e('th', null, 'Last Modified')
|
||||
e("th", null, "Name"),
|
||||
e("th", null, "Type"),
|
||||
e("th", null, "Size"),
|
||||
e("th", null, "Last Modified")
|
||||
)
|
||||
),
|
||||
e('tbody', null, rows)
|
||||
e("tbody", null, rows)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
const React = require('react')
|
||||
const semver = require('semver')
|
||||
const DirectoryListing = require('./DirectoryListing')
|
||||
const readCSS = require('../utils/readCSS')
|
||||
const React = require("react")
|
||||
const semver = require("semver")
|
||||
const DirectoryListing = require("./DirectoryListing")
|
||||
const readCSS = require("../utils/readCSS")
|
||||
|
||||
const e = React.createElement
|
||||
|
||||
const IndexPageStyle = readCSS(__dirname, 'IndexPage.css')
|
||||
const IndexPageStyle = readCSS(__dirname, "IndexPage.css")
|
||||
const IndexPageScript = `
|
||||
var s = document.getElementById('version'), v = s.value
|
||||
s.onchange = function () {
|
||||
@ -17,37 +17,35 @@ const byVersion = (a, b) => (semver.lt(a, b) ? -1 : semver.gt(a, b) ? 1 : 0)
|
||||
|
||||
const IndexPage = ({ packageInfo, version, dir, entries }) => {
|
||||
const versions = Object.keys(packageInfo.versions).sort(byVersion)
|
||||
const options = versions.map(v =>
|
||||
e('option', { key: v, value: v }, `${packageInfo.name}@${v}`)
|
||||
)
|
||||
const options = versions.map(v => e("option", { key: v, value: v }, `${packageInfo.name}@${v}`))
|
||||
|
||||
return e(
|
||||
'html',
|
||||
"html",
|
||||
null,
|
||||
e(
|
||||
'head',
|
||||
"head",
|
||||
null,
|
||||
e('meta', { charSet: 'utf-8' }),
|
||||
e('title', null, `Index of ${dir}`),
|
||||
e('style', { dangerouslySetInnerHTML: { __html: IndexPageStyle } })
|
||||
e("meta", { charSet: "utf-8" }),
|
||||
e("title", null, `Index of ${dir}`),
|
||||
e("style", { dangerouslySetInnerHTML: { __html: IndexPageStyle } })
|
||||
),
|
||||
e(
|
||||
'body',
|
||||
"body",
|
||||
null,
|
||||
e(
|
||||
'div',
|
||||
{ className: 'content-wrapper' },
|
||||
"div",
|
||||
{ className: "content-wrapper" },
|
||||
e(
|
||||
'div',
|
||||
{ className: 'version-wrapper' },
|
||||
e('select', { id: 'version', defaultValue: version }, options)
|
||||
"div",
|
||||
{ className: "version-wrapper" },
|
||||
e("select", { id: "version", defaultValue: version }, options)
|
||||
),
|
||||
e('h1', null, `Index of ${dir}`),
|
||||
e('script', { dangerouslySetInnerHTML: { __html: IndexPageScript } }),
|
||||
e('hr'),
|
||||
e("h1", null, `Index of ${dir}`),
|
||||
e("script", { dangerouslySetInnerHTML: { __html: IndexPageScript } }),
|
||||
e("hr"),
|
||||
e(DirectoryListing, { dir, entries }),
|
||||
e('hr'),
|
||||
e('address', null, `${packageInfo.name}@${version}`)
|
||||
e("hr"),
|
||||
e("address", null, `${packageInfo.name}@${version}`)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -1,11 +1,11 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const semver = require('semver')
|
||||
const createPackageURL = require('../utils/createPackageURL')
|
||||
const createSearch = require('./utils/createSearch')
|
||||
const getPackageInfo = require('./utils/getPackageInfo')
|
||||
const getPackage = require('./utils/getPackage')
|
||||
const incrementCounter = require('./utils/incrementCounter')
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const semver = require("semver")
|
||||
const createPackageURL = require("../utils/createPackageURL")
|
||||
const createSearch = require("./utils/createSearch")
|
||||
const getPackageInfo = require("./utils/getPackageInfo")
|
||||
const getPackage = require("./utils/getPackage")
|
||||
const incrementCounter = require("./utils/incrementCounter")
|
||||
|
||||
function getBasename(file) {
|
||||
return path.basename(file, path.extname(file))
|
||||
@ -14,7 +14,7 @@ function getBasename(file) {
|
||||
/**
|
||||
* File extensions to look for when automatically resolving.
|
||||
*/
|
||||
const FindExtensions = ['', '.js', '.json']
|
||||
const FindExtensions = ["", ".js", ".json"]
|
||||
|
||||
/**
|
||||
* Resolves a path like "lib/file" into "lib/file.js" or "lib/file.json"
|
||||
@ -27,17 +27,13 @@ function findFile(base, useIndex, callback) {
|
||||
return function() {
|
||||
fs.stat(file, function(error, stats) {
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') {
|
||||
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
||||
next()
|
||||
} else {
|
||||
callback(error)
|
||||
}
|
||||
} else if (useIndex && stats.isDirectory()) {
|
||||
findFile(path.join(file, 'index'), false, function(
|
||||
error,
|
||||
indexFile,
|
||||
indexStats
|
||||
) {
|
||||
findFile(path.join(file, "index"), false, function(error, indexFile, indexStats) {
|
||||
if (error) {
|
||||
callback(error)
|
||||
} else if (indexFile) {
|
||||
@ -65,14 +61,14 @@ function fetchFile(req, res, next) {
|
||||
console.error(error)
|
||||
return res
|
||||
.status(500)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Cannot get info for package "${req.packageName}"`)
|
||||
}
|
||||
|
||||
if (packageInfo == null || packageInfo.versions == null)
|
||||
return res
|
||||
.status(404)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Cannot find package "${req.packageName}"`)
|
||||
|
||||
req.packageInfo = packageInfo
|
||||
@ -86,7 +82,7 @@ function fetchFile(req, res, next) {
|
||||
console.error(error)
|
||||
res
|
||||
.status(500)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Cannot fetch package ${req.packageSpec}`)
|
||||
} else {
|
||||
req.packageDir = outputDir
|
||||
@ -98,77 +94,56 @@ function fetchFile(req, res, next) {
|
||||
// They want an ES module. Try "module", "jsnext:main", and "/"
|
||||
// https://github.com/rollup/rollup/wiki/pkg.module
|
||||
if (!filename)
|
||||
filename =
|
||||
req.packageConfig.module ||
|
||||
req.packageConfig['jsnext:main'] ||
|
||||
'/'
|
||||
filename = req.packageConfig.module || req.packageConfig["jsnext:main"] || "/"
|
||||
} else if (filename) {
|
||||
// They are requesting an explicit filename. Only try to find an
|
||||
// index file if they are NOT requesting an HTML directory listing.
|
||||
useIndex = filename[filename.length - 1] !== '/'
|
||||
} else if (
|
||||
req.query.main &&
|
||||
typeof req.packageConfig[req.query.main] === 'string'
|
||||
) {
|
||||
useIndex = filename[filename.length - 1] !== "/"
|
||||
} else if (req.query.main && typeof req.packageConfig[req.query.main] === "string") {
|
||||
// They specified a custom ?main field.
|
||||
filename = req.packageConfig[req.query.main]
|
||||
|
||||
incrementCounter(
|
||||
'package-json-custom-main',
|
||||
req.packageSpec + '?main=' + req.query.main,
|
||||
"package-json-custom-main",
|
||||
req.packageSpec + "?main=" + req.query.main,
|
||||
1
|
||||
)
|
||||
} else if (typeof req.packageConfig.unpkg === 'string') {
|
||||
} else if (typeof req.packageConfig.unpkg === "string") {
|
||||
// The "unpkg" field allows packages to explicitly declare the
|
||||
// file to serve at the bare URL (see #59).
|
||||
filename = req.packageConfig.unpkg
|
||||
} else if (typeof req.packageConfig.browser === 'string') {
|
||||
} else if (typeof req.packageConfig.browser === "string") {
|
||||
// Fall back to the "browser" field if declared (only support strings).
|
||||
filename = req.packageConfig.browser
|
||||
|
||||
// Count which packages + versions are actually using this fallback
|
||||
// so we can warn them when we deprecate this functionality.
|
||||
// See https://github.com/unpkg/unpkg/issues/63
|
||||
incrementCounter(
|
||||
'package-json-browser-fallback',
|
||||
req.packageSpec,
|
||||
1
|
||||
)
|
||||
incrementCounter("package-json-browser-fallback", req.packageSpec, 1)
|
||||
} else {
|
||||
// Fall back to "main" or / (same as npm).
|
||||
filename = req.packageConfig.main || '/'
|
||||
filename = req.packageConfig.main || "/"
|
||||
}
|
||||
|
||||
findFile(path.join(req.packageDir, filename), useIndex, function(
|
||||
error,
|
||||
file,
|
||||
stats
|
||||
) {
|
||||
findFile(path.join(req.packageDir, filename), useIndex, function(error, file, stats) {
|
||||
if (error) console.error(error)
|
||||
|
||||
if (file == null)
|
||||
return res
|
||||
.status(404)
|
||||
.type('text')
|
||||
.send(
|
||||
`Cannot find module "${filename}" in package ${
|
||||
req.packageSpec
|
||||
}`
|
||||
)
|
||||
.type("text")
|
||||
.send(`Cannot find module "${filename}" in package ${req.packageSpec}`)
|
||||
|
||||
filename = file.replace(req.packageDir, '')
|
||||
filename = file.replace(req.packageDir, "")
|
||||
|
||||
if (
|
||||
req.query.main != null ||
|
||||
getBasename(req.filename) !== getBasename(filename)
|
||||
) {
|
||||
if (req.query.main != null || getBasename(req.filename) !== getBasename(filename)) {
|
||||
// Need to redirect to the module file so relative imports resolve
|
||||
// correctly. Cache module redirects for 1 minute.
|
||||
delete req.query.main
|
||||
res
|
||||
.set({
|
||||
'Cache-Control': 'public, max-age=60',
|
||||
'Cache-Tag': 'redirect,module-redirect'
|
||||
"Cache-Control": "public, max-age=60",
|
||||
"Cache-Tag": "redirect,module-redirect"
|
||||
})
|
||||
.redirect(
|
||||
302,
|
||||
@ -187,18 +162,18 @@ function fetchFile(req, res, next) {
|
||||
})
|
||||
}
|
||||
})
|
||||
} else if (req.packageVersion in req.packageInfo['dist-tags']) {
|
||||
} else if (req.packageVersion in req.packageInfo["dist-tags"]) {
|
||||
// Cache tag redirects for 1 minute.
|
||||
res
|
||||
.set({
|
||||
'Cache-Control': 'public, max-age=60',
|
||||
'Cache-Tag': 'redirect,tag-redirect'
|
||||
"Cache-Control": "public, max-age=60",
|
||||
"Cache-Tag": "redirect,tag-redirect"
|
||||
})
|
||||
.redirect(
|
||||
302,
|
||||
createPackageURL(
|
||||
req.packageName,
|
||||
req.packageInfo['dist-tags'][req.packageVersion],
|
||||
req.packageInfo["dist-tags"][req.packageVersion],
|
||||
req.filename,
|
||||
req.search
|
||||
)
|
||||
@ -213,22 +188,14 @@ function fetchFile(req, res, next) {
|
||||
// Cache semver redirects for 1 minute.
|
||||
res
|
||||
.set({
|
||||
'Cache-Control': 'public, max-age=60',
|
||||
'Cache-Tag': 'redirect,semver-redirect'
|
||||
"Cache-Control": "public, max-age=60",
|
||||
"Cache-Tag": "redirect,semver-redirect"
|
||||
})
|
||||
.redirect(
|
||||
302,
|
||||
createPackageURL(
|
||||
req.packageName,
|
||||
maxVersion,
|
||||
req.filename,
|
||||
req.search
|
||||
)
|
||||
)
|
||||
.redirect(302, createPackageURL(req.packageName, maxVersion, req.filename, req.search))
|
||||
} else {
|
||||
res
|
||||
.status(404)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Cannot find package ${req.packageSpec}`)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
const validateNpmPackageName = require('validate-npm-package-name')
|
||||
const parsePackageURL = require('../utils/parsePackageURL')
|
||||
const createSearch = require('./utils/createSearch')
|
||||
const validateNpmPackageName = require("validate-npm-package-name")
|
||||
const parsePackageURL = require("../utils/parsePackageURL")
|
||||
const createSearch = require("./utils/createSearch")
|
||||
|
||||
const KnownQueryParams = {
|
||||
main: true,
|
||||
@ -32,14 +32,14 @@ function sanitizeQuery(query) {
|
||||
function parseURL(req, res, next) {
|
||||
// Redirect /_meta/path to /path?meta.
|
||||
if (req.path.match(/^\/_meta\//)) {
|
||||
req.query.meta = ''
|
||||
req.query.meta = ""
|
||||
return res.redirect(302, req.path.substr(6) + createSearch(req.query))
|
||||
}
|
||||
|
||||
// Redirect /path?json => /path?meta
|
||||
if (req.query.json != null) {
|
||||
delete req.query.json
|
||||
req.query.meta = ''
|
||||
req.query.meta = ""
|
||||
return res.redirect(302, req.path + createSearch(req.query))
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ function parseURL(req, res, next) {
|
||||
if (url == null) {
|
||||
return res
|
||||
.status(403)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Invalid URL: ${req.url}`)
|
||||
}
|
||||
|
||||
@ -64,10 +64,10 @@ function parseURL(req, res, next) {
|
||||
|
||||
// Disallow invalid package names.
|
||||
if (nameErrors) {
|
||||
const reason = nameErrors.join(', ')
|
||||
const reason = nameErrors.join(", ")
|
||||
return res
|
||||
.status(403)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Invalid package name "${url.packageName}" (${reason})`)
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,9 @@
|
||||
*/
|
||||
function requireAuth(scope) {
|
||||
let checkScopes
|
||||
if (scope.includes('.')) {
|
||||
const parts = scope.split('.')
|
||||
checkScopes = scopes =>
|
||||
parts.reduce((memo, part) => memo && memo[part], scopes) != null
|
||||
if (scope.includes(".")) {
|
||||
const parts = scope.split(".")
|
||||
checkScopes = scopes => parts.reduce((memo, part) => memo && memo[part], scopes) != null
|
||||
} else {
|
||||
checkScopes = scopes => scopes[scope] != null
|
||||
}
|
||||
@ -20,11 +19,11 @@ function requireAuth(scope) {
|
||||
const user = req.user
|
||||
|
||||
if (!user) {
|
||||
return res.status(403).send({ error: 'Missing auth token' })
|
||||
return res.status(403).send({ error: "Missing auth token" })
|
||||
}
|
||||
|
||||
if (!user.scopes || !checkScopes(user.scopes)) {
|
||||
return res.status(403).send({ error: 'Insufficient scopes' })
|
||||
return res.status(403).send({ error: "Insufficient scopes" })
|
||||
}
|
||||
|
||||
if (req.auth) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const etag = require('etag')
|
||||
const babel = require('babel-core')
|
||||
const unpkgRewrite = require('babel-plugin-unpkg-rewrite')
|
||||
const getMetadata = require('./utils/getMetadata')
|
||||
const getFileContentType = require('./utils/getFileContentType')
|
||||
const getIndexHTML = require('./utils/getIndexHTML')
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const etag = require("etag")
|
||||
const babel = require("babel-core")
|
||||
const unpkgRewrite = require("babel-plugin-unpkg-rewrite")
|
||||
const getMetadata = require("./utils/getMetadata")
|
||||
const getFileContentType = require("./utils/getFileContentType")
|
||||
const getIndexHTML = require("./utils/getIndexHTML")
|
||||
|
||||
/**
|
||||
* Automatically generate HTML pages that show package contents.
|
||||
@ -35,24 +35,19 @@ const FileTransforms = {
|
||||
function serveFile(req, res, next) {
|
||||
if (req.query.meta != null) {
|
||||
// Serve JSON metadata.
|
||||
getMetadata(req.packageDir, req.filename, req.stats, MaximumDepth, function(
|
||||
error,
|
||||
metadata
|
||||
) {
|
||||
getMetadata(req.packageDir, req.filename, req.stats, MaximumDepth, function(error, metadata) {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
res
|
||||
.status(500)
|
||||
.type('text')
|
||||
.send(
|
||||
`Cannot generate metadata for ${req.packageSpec}${req.filename}`
|
||||
)
|
||||
.type("text")
|
||||
.send(`Cannot generate metadata for ${req.packageSpec}${req.filename}`)
|
||||
} else {
|
||||
// Cache metadata for 1 year.
|
||||
res
|
||||
.set({
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
'Cache-Tag': 'meta'
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Cache-Tag": "meta"
|
||||
})
|
||||
.send(metadata)
|
||||
}
|
||||
@ -63,9 +58,9 @@ function serveFile(req, res, next) {
|
||||
|
||||
let contentType = getFileContentType(file)
|
||||
|
||||
if (contentType === 'text/html') contentType = 'text/plain' // We can't serve HTML because bad people :(
|
||||
if (contentType === "text/html") contentType = "text/plain" // We can't serve HTML because bad people :(
|
||||
|
||||
if (contentType === 'application/javascript' && req.query.module != null) {
|
||||
if (contentType === "application/javascript" && req.query.module != null) {
|
||||
// Serve a JavaScript module.
|
||||
const dependencies = Object.assign(
|
||||
{},
|
||||
@ -78,33 +73,29 @@ function serveFile(req, res, next) {
|
||||
console.error(error)
|
||||
const debugInfo =
|
||||
error.constructor.name +
|
||||
': ' +
|
||||
": " +
|
||||
error.message.replace(/^.*?\/unpkg-.+?\//, `/${req.packageSpec}/`) +
|
||||
'\n\n' +
|
||||
"\n\n" +
|
||||
error.codeFrame
|
||||
res
|
||||
.status(500)
|
||||
.type('text')
|
||||
.send(
|
||||
`Cannot generate module for ${req.packageSpec}${
|
||||
req.filename
|
||||
}\n\n${debugInfo}`
|
||||
)
|
||||
.type("text")
|
||||
.send(`Cannot generate module for ${req.packageSpec}${req.filename}\n\n${debugInfo}`)
|
||||
} else {
|
||||
// Cache modules for 1 year.
|
||||
res
|
||||
.set({
|
||||
'Content-Type': contentType,
|
||||
'Content-Length': Buffer.byteLength(code),
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
'Cache-Tag': 'file,js-file,js-module'
|
||||
"Content-Type": contentType,
|
||||
"Content-Length": Buffer.byteLength(code),
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Cache-Tag": "file,js-file,js-module"
|
||||
})
|
||||
.send(code)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// Serve some other static file.
|
||||
const tags = ['file']
|
||||
const tags = ["file"]
|
||||
|
||||
const ext = path.extname(req.filename).substr(1)
|
||||
|
||||
@ -112,17 +103,17 @@ function serveFile(req, res, next) {
|
||||
|
||||
// Cache files for 1 year.
|
||||
res.set({
|
||||
'Content-Type': contentType,
|
||||
'Content-Length': req.stats.size,
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
'Last-Modified': req.stats.mtime.toUTCString(),
|
||||
"Content-Type": contentType,
|
||||
"Content-Length": req.stats.size,
|
||||
"Cache-Control": "public, max-age=31536000",
|
||||
"Last-Modified": req.stats.mtime.toUTCString(),
|
||||
ETag: etag(req.stats),
|
||||
'Cache-Tag': tags.join(',')
|
||||
"Cache-Tag": tags.join(",")
|
||||
})
|
||||
|
||||
const stream = fs.createReadStream(file)
|
||||
|
||||
stream.on('error', function(error) {
|
||||
stream.on("error", function(error) {
|
||||
console.error(`Cannot send file ${req.packageSpec}${req.filename}`)
|
||||
console.error(error)
|
||||
res.sendStatus(500)
|
||||
@ -132,35 +123,30 @@ function serveFile(req, res, next) {
|
||||
}
|
||||
} else if (AutoIndex && req.stats.isDirectory()) {
|
||||
// Serve an HTML directory listing.
|
||||
getIndexHTML(
|
||||
req.packageInfo,
|
||||
req.packageVersion,
|
||||
req.packageDir,
|
||||
req.filename,
|
||||
function(error, html) {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
res
|
||||
.status(500)
|
||||
.type('text')
|
||||
.send(
|
||||
`Cannot generate index page for ${req.packageSpec}${req.filename}`
|
||||
)
|
||||
} else {
|
||||
// Cache HTML directory listings for 1 minute.
|
||||
res
|
||||
.set({
|
||||
'Cache-Control': 'public, max-age=60',
|
||||
'Cache-Tag': 'index'
|
||||
})
|
||||
.send(html)
|
||||
}
|
||||
getIndexHTML(req.packageInfo, req.packageVersion, req.packageDir, req.filename, function(
|
||||
error,
|
||||
html
|
||||
) {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
res
|
||||
.status(500)
|
||||
.type("text")
|
||||
.send(`Cannot generate index page for ${req.packageSpec}${req.filename}`)
|
||||
} else {
|
||||
// Cache HTML directory listings for 1 minute.
|
||||
res
|
||||
.set({
|
||||
"Cache-Control": "public, max-age=60",
|
||||
"Cache-Tag": "index"
|
||||
})
|
||||
.send(html)
|
||||
}
|
||||
)
|
||||
})
|
||||
} else {
|
||||
res
|
||||
.status(403)
|
||||
.type('text')
|
||||
.type("text")
|
||||
.send(`Cannot serve ${req.packageSpec}${req.filename}; it's not a file`)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
const AuthAPI = require('../AuthAPI')
|
||||
const AuthAPI = require("../AuthAPI")
|
||||
|
||||
const ReadMethods = { GET: true, HEAD: true }
|
||||
|
||||
@ -23,7 +23,7 @@ function userToken(req, res, next) {
|
||||
next()
|
||||
},
|
||||
error => {
|
||||
if (error.name === 'JsonWebTokenError') {
|
||||
if (error.name === "JsonWebTokenError") {
|
||||
res.status(403).send({
|
||||
error: `Bad auth token: ${error.message}`
|
||||
})
|
||||
@ -31,7 +31,7 @@ function userToken(req, res, next) {
|
||||
console.error(error)
|
||||
|
||||
res.status(500).send({
|
||||
error: 'Unable to verify auth'
|
||||
error: "Unable to verify auth"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
const getFileContentType = require('../getFileContentType')
|
||||
const getFileContentType = require("../getFileContentType")
|
||||
|
||||
it('gets a content type of text/plain for LICENSE|README|CHANGES|AUTHORS|Makefile', () => {
|
||||
expect(getFileContentType('AUTHORS')).toBe('text/plain')
|
||||
expect(getFileContentType('CHANGES')).toBe('text/plain')
|
||||
expect(getFileContentType('LICENSE')).toBe('text/plain')
|
||||
expect(getFileContentType('Makefile')).toBe('text/plain')
|
||||
expect(getFileContentType('PATENTS')).toBe('text/plain')
|
||||
expect(getFileContentType('README')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for LICENSE|README|CHANGES|AUTHORS|Makefile", () => {
|
||||
expect(getFileContentType("AUTHORS")).toBe("text/plain")
|
||||
expect(getFileContentType("CHANGES")).toBe("text/plain")
|
||||
expect(getFileContentType("LICENSE")).toBe("text/plain")
|
||||
expect(getFileContentType("Makefile")).toBe("text/plain")
|
||||
expect(getFileContentType("PATENTS")).toBe("text/plain")
|
||||
expect(getFileContentType("README")).toBe("text/plain")
|
||||
})
|
||||
|
||||
it('gets a content type of text/plain for .*rc files', () => {
|
||||
expect(getFileContentType('.eslintrc')).toBe('text/plain')
|
||||
expect(getFileContentType('.babelrc')).toBe('text/plain')
|
||||
expect(getFileContentType('.anythingrc')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for .*rc files", () => {
|
||||
expect(getFileContentType(".eslintrc")).toBe("text/plain")
|
||||
expect(getFileContentType(".babelrc")).toBe("text/plain")
|
||||
expect(getFileContentType(".anythingrc")).toBe("text/plain")
|
||||
})
|
||||
|
||||
it('gets a content type of text/plain for .git* files', () => {
|
||||
expect(getFileContentType('.gitignore')).toBe('text/plain')
|
||||
expect(getFileContentType('.gitanything')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for .git* files", () => {
|
||||
expect(getFileContentType(".gitignore")).toBe("text/plain")
|
||||
expect(getFileContentType(".gitanything")).toBe("text/plain")
|
||||
})
|
||||
|
||||
it('gets a content type of text/plain for .*ignore files', () => {
|
||||
expect(getFileContentType('.eslintignore')).toBe('text/plain')
|
||||
expect(getFileContentType('.anythingignore')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for .*ignore files", () => {
|
||||
expect(getFileContentType(".eslintignore")).toBe("text/plain")
|
||||
expect(getFileContentType(".anythingignore")).toBe("text/plain")
|
||||
})
|
||||
|
||||
it('gets a content type of text/plain for .ts files', () => {
|
||||
expect(getFileContentType('app.ts')).toBe('text/plain')
|
||||
expect(getFileContentType('app.d.ts')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for .ts files", () => {
|
||||
expect(getFileContentType("app.ts")).toBe("text/plain")
|
||||
expect(getFileContentType("app.d.ts")).toBe("text/plain")
|
||||
})
|
||||
|
||||
it('gets a content type of text/plain for .flow files', () => {
|
||||
expect(getFileContentType('app.js.flow')).toBe('text/plain')
|
||||
it("gets a content type of text/plain for .flow files", () => {
|
||||
expect(getFileContentType("app.js.flow")).toBe("text/plain")
|
||||
})
|
||||
|
@ -1,8 +1,8 @@
|
||||
const db = require('../../RedisClient')
|
||||
const db = require("../../RedisClient")
|
||||
|
||||
function createCache(keyPrefix) {
|
||||
function createKey(key) {
|
||||
return keyPrefix + '-' + key
|
||||
return keyPrefix + "-" + key
|
||||
}
|
||||
|
||||
function set(key, value, expiry, callback) {
|
||||
|
@ -2,16 +2,16 @@ function createSearch(query) {
|
||||
const params = []
|
||||
|
||||
Object.keys(query).forEach(param => {
|
||||
if (query[param] === '') {
|
||||
if (query[param] === "") {
|
||||
params.push(param) // Omit the trailing "=" from param=
|
||||
} else {
|
||||
params.push(`${param}=${encodeURIComponent(query[param])}`)
|
||||
}
|
||||
})
|
||||
|
||||
const search = params.join('&')
|
||||
const search = params.join("&")
|
||||
|
||||
return search ? `?${search}` : ''
|
||||
return search ? `?${search}` : ""
|
||||
}
|
||||
|
||||
module.exports = createSearch
|
||||
|
@ -1,22 +1,13 @@
|
||||
const mime = require('mime')
|
||||
const mime = require("mime")
|
||||
|
||||
mime.define({
|
||||
'text/plain': [
|
||||
'authors',
|
||||
'changes',
|
||||
'license',
|
||||
'makefile',
|
||||
'patents',
|
||||
'readme',
|
||||
'ts',
|
||||
'flow'
|
||||
]
|
||||
"text/plain": ["authors", "changes", "license", "makefile", "patents", "readme", "ts", "flow"]
|
||||
})
|
||||
|
||||
const TextFiles = /\/?(\.[a-z]*rc|\.git[a-z]*|\.[a-z]*ignore)$/i
|
||||
|
||||
function getFileContentType(file) {
|
||||
return TextFiles.test(file) ? 'text/plain' : mime.lookup(file)
|
||||
return TextFiles.test(file) ? "text/plain" : mime.lookup(file)
|
||||
}
|
||||
|
||||
module.exports = getFileContentType
|
||||
|
@ -1,4 +1,4 @@
|
||||
const fs = require('fs')
|
||||
const fs = require("fs")
|
||||
|
||||
function getFileStats(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1,12 +1,12 @@
|
||||
function getFileType(stats) {
|
||||
if (stats.isFile()) return 'file'
|
||||
if (stats.isDirectory()) return 'directory'
|
||||
if (stats.isBlockDevice()) return 'blockDevice'
|
||||
if (stats.isCharacterDevice()) return 'characterDevice'
|
||||
if (stats.isSymbolicLink()) return 'symlink'
|
||||
if (stats.isSocket()) return 'socket'
|
||||
if (stats.isFIFO()) return 'fifo'
|
||||
return 'unknown'
|
||||
if (stats.isFile()) return "file"
|
||||
if (stats.isDirectory()) return "directory"
|
||||
if (stats.isBlockDevice()) return "blockDevice"
|
||||
if (stats.isCharacterDevice()) return "characterDevice"
|
||||
if (stats.isSymbolicLink()) return "symlink"
|
||||
if (stats.isSocket()) return "socket"
|
||||
if (stats.isFIFO()) return "fifo"
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
module.exports = getFileType
|
||||
|
@ -1,9 +1,9 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const React = require('react')
|
||||
const ReactDOMServer = require('react-dom/server')
|
||||
const getFileStats = require('./getFileStats')
|
||||
const IndexPage = require('../components/IndexPage')
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const React = require("react")
|
||||
const ReactDOMServer = require("react-dom/server")
|
||||
const getFileStats = require("./getFileStats")
|
||||
const IndexPage = require("../components/IndexPage")
|
||||
|
||||
const e = React.createElement
|
||||
|
||||
@ -14,9 +14,7 @@ function getEntries(dir) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(
|
||||
Promise.all(
|
||||
files.map(file => getFileStats(path.join(dir, file)))
|
||||
).then(statsArray => {
|
||||
Promise.all(files.map(file => getFileStats(path.join(dir, file)))).then(statsArray => {
|
||||
return statsArray.map((stats, index) => {
|
||||
return { file: files[index], stats }
|
||||
})
|
||||
@ -27,7 +25,7 @@ function getEntries(dir) {
|
||||
})
|
||||
}
|
||||
|
||||
const DOCTYPE = '<!DOCTYPE html>'
|
||||
const DOCTYPE = "<!DOCTYPE html>"
|
||||
|
||||
function createHTML(props) {
|
||||
return DOCTYPE + ReactDOMServer.renderToStaticMarkup(e(IndexPage, props))
|
||||
|
@ -1,9 +1,9 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const SRIToolbox = require('sri-toolbox')
|
||||
const getFileContentType = require('./getFileContentType')
|
||||
const getFileStats = require('./getFileStats')
|
||||
const getFileType = require('./getFileType')
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const SRIToolbox = require("sri-toolbox")
|
||||
const getFileContentType = require("./getFileContentType")
|
||||
const getFileStats = require("./getFileStats")
|
||||
const getFileType = require("./getFileType")
|
||||
|
||||
function getEntries(dir, file, maximumDepth) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -12,17 +12,10 @@ function getEntries(dir, file, maximumDepth) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(
|
||||
Promise.all(
|
||||
files.map(f => getFileStats(path.join(dir, file, f)))
|
||||
).then(statsArray => {
|
||||
Promise.all(files.map(f => getFileStats(path.join(dir, file, f)))).then(statsArray => {
|
||||
return Promise.all(
|
||||
statsArray.map((stats, index) =>
|
||||
getMetadataRecursive(
|
||||
dir,
|
||||
path.join(file, files[index]),
|
||||
stats,
|
||||
maximumDepth - 1
|
||||
)
|
||||
getMetadataRecursive(dir, path.join(file, files[index]), stats, maximumDepth - 1)
|
||||
)
|
||||
)
|
||||
})
|
||||
@ -42,7 +35,7 @@ function getIntegrity(file) {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(SRIToolbox.generate({ algorithms: ['sha384'] }, data))
|
||||
resolve(SRIToolbox.generate({ algorithms: ["sha384"] }, data))
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -64,8 +57,7 @@ function getMetadataRecursive(dir, file, stats, maximumDepth) {
|
||||
})
|
||||
}
|
||||
|
||||
if (!stats.isDirectory() || maximumDepth === 0)
|
||||
return Promise.resolve(metadata)
|
||||
if (!stats.isDirectory() || maximumDepth === 0) return Promise.resolve(metadata)
|
||||
|
||||
return getEntries(dir, file, maximumDepth).then(files => {
|
||||
metadata.files = files
|
||||
@ -74,12 +66,9 @@ function getMetadataRecursive(dir, file, stats, maximumDepth) {
|
||||
}
|
||||
|
||||
function getMetadata(baseDir, path, stats, maximumDepth, callback) {
|
||||
getMetadataRecursive(baseDir, path, stats, maximumDepth).then(function(
|
||||
metadata
|
||||
) {
|
||||
getMetadataRecursive(baseDir, path, stats, maximumDepth).then(function(metadata) {
|
||||
callback(null, metadata)
|
||||
},
|
||||
callback)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
module.exports = getMetadata
|
||||
|
@ -1,14 +1,14 @@
|
||||
require('isomorphic-fetch')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const tmpdir = require('os-tmpdir')
|
||||
const gunzip = require('gunzip-maybe')
|
||||
const mkdirp = require('mkdirp')
|
||||
const tar = require('tar-fs')
|
||||
const createMutex = require('./createMutex')
|
||||
require("isomorphic-fetch")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const tmpdir = require("os-tmpdir")
|
||||
const gunzip = require("gunzip-maybe")
|
||||
const mkdirp = require("mkdirp")
|
||||
const tar = require("tar-fs")
|
||||
const createMutex = require("./createMutex")
|
||||
|
||||
function createTempPath(name, version) {
|
||||
const normalName = name.replace(/\//g, '-')
|
||||
const normalName = name.replace(/\//g, "-")
|
||||
return path.join(tmpdir(), `unpkg-${normalName}-${version}`)
|
||||
}
|
||||
|
||||
@ -17,12 +17,12 @@ function stripNamePrefix(headers) {
|
||||
// so we shorten that to just "index.js" here. A few packages use a
|
||||
// prefix other than "package/". e.g. the firebase package uses the
|
||||
// "firebase_npm/" prefix. So we just strip the first dir name.
|
||||
headers.name = headers.name.replace(/^[^\/]+\//, '')
|
||||
headers.name = headers.name.replace(/^[^\/]+\//, "")
|
||||
return headers
|
||||
}
|
||||
|
||||
function ignoreSymlinks(file, headers) {
|
||||
return headers.type === 'link'
|
||||
return headers.type === "link"
|
||||
}
|
||||
|
||||
function extractResponse(response, outputDir) {
|
||||
@ -36,8 +36,8 @@ function extractResponse(response, outputDir) {
|
||||
response.body
|
||||
.pipe(gunzip())
|
||||
.pipe(extract)
|
||||
.on('finish', resolve)
|
||||
.on('error', reject)
|
||||
.on("finish", resolve)
|
||||
.on("error", reject)
|
||||
})
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ const fetchMutex = createMutex((payload, callback) => {
|
||||
|
||||
fs.access(outputDir, function(error) {
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') {
|
||||
if (error.code === "ENOENT" || error.code === "ENOTDIR") {
|
||||
// ENOENT or ENOTDIR are to be expected when we haven't yet
|
||||
// fetched a package for the first time. Carry on!
|
||||
mkdirp(outputDir, function(error) {
|
||||
|
@ -1,16 +1,16 @@
|
||||
require('isomorphic-fetch')
|
||||
const createCache = require('./createCache')
|
||||
const createMutex = require('./createMutex')
|
||||
require("isomorphic-fetch")
|
||||
const createCache = require("./createCache")
|
||||
const createMutex = require("./createMutex")
|
||||
|
||||
const RegistryURL = process.env.NPM_REGISTRY_URL || 'https://registry.npmjs.org'
|
||||
const RegistryURL = process.env.NPM_REGISTRY_URL || "https://registry.npmjs.org"
|
||||
|
||||
const PackageInfoCache = createCache('packageInfo')
|
||||
const PackageInfoCache = createCache("packageInfo")
|
||||
|
||||
function fetchPackageInfo(packageName) {
|
||||
console.log(`info: Fetching package info for ${packageName}`)
|
||||
|
||||
let encodedPackageName
|
||||
if (packageName.charAt(0) === '@') {
|
||||
if (packageName.charAt(0) === "@") {
|
||||
encodedPackageName = `@${encodeURIComponent(packageName.substring(1))}`
|
||||
} else {
|
||||
encodedPackageName = encodeURIComponent(packageName)
|
||||
@ -20,14 +20,14 @@ function fetchPackageInfo(packageName) {
|
||||
|
||||
return fetch(url, {
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
Accept: "application/json"
|
||||
}
|
||||
}).then(res => {
|
||||
return res.status === 404 ? null : res.json()
|
||||
})
|
||||
}
|
||||
|
||||
const PackageNotFound = 'PackageNotFound'
|
||||
const PackageNotFound = "PackageNotFound"
|
||||
|
||||
// This mutex prevents multiple concurrent requests to
|
||||
// the registry for the same package info.
|
||||
|
@ -1,4 +1,4 @@
|
||||
const db = require('../../RedisClient')
|
||||
const db = require("../../RedisClient")
|
||||
|
||||
function incrementCounter(counter, key, by) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -1,9 +1,9 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const csso = require('csso')
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const csso = require("csso")
|
||||
|
||||
function readCSS(...args) {
|
||||
return csso.minify(fs.readFileSync(path.resolve(...args), 'utf8')).css
|
||||
return csso.minify(fs.readFileSync(path.resolve(...args), "utf8")).css
|
||||
}
|
||||
|
||||
module.exports = readCSS
|
||||
|
@ -1,4 +1,4 @@
|
||||
const parsePackageURL = require('../utils/parsePackageURL')
|
||||
const parsePackageURL = require("../utils/parsePackageURL")
|
||||
|
||||
/**
|
||||
* Adds various properties to the request object to do with the
|
||||
|
Reference in New Issue
Block a user