Add /_meta endpoint for metadata
Also, add integrity values to metadata.
This commit is contained in:
parent
bc609ca825
commit
666d8afc95
|
@ -32,6 +32,7 @@
|
|||
"react-router-dom": "^4.0.0",
|
||||
"redis": "^2.7.1",
|
||||
"semver": "^5.3.0",
|
||||
"sri-toolbox": "^0.2.0",
|
||||
"tar-fs": "^1.15.2",
|
||||
"throng": "^4.0.0",
|
||||
"validate-npm-package-name": "^3.0.0"
|
||||
|
|
|
@ -9,6 +9,7 @@ const { fetchStats } = require('./cloudflare')
|
|||
const parsePackageURL = require('./middleware/parsePackageURL')
|
||||
const fetchFile = require('./middleware/fetchFile')
|
||||
const serveFile = require('./middleware/serveFile')
|
||||
const serveMetadata = require('./middleware/serveMetadata')
|
||||
|
||||
morgan.token('fwd', function (req) {
|
||||
return req.get('x-forwarded-for').replace(/\s/g, '')
|
||||
|
@ -66,9 +67,8 @@ function createServer() {
|
|||
maxAge: '365d'
|
||||
}))
|
||||
|
||||
app.use(parsePackageURL)
|
||||
app.use(fetchFile)
|
||||
app.use(serveFile)
|
||||
app.use('/_meta', parsePackageURL, fetchFile, serveMetadata)
|
||||
app.use('/', parsePackageURL, fetchFile, serveFile)
|
||||
|
||||
const server = http.createServer(app)
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const SRIToolbox = require('sri-toolbox')
|
||||
const { getContentType, getStats, getFileType } = require('./FileUtils')
|
||||
|
||||
function getEntries(dir, file, maximumDepth) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readdir(path.join(dir, file), (error, files) => {
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readdir(path.join(dir, file), function (error, files) {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
|
@ -15,7 +16,7 @@ function getEntries(dir, file, maximumDepth) {
|
|||
})
|
||||
).then(function (statsArray) {
|
||||
return Promise.all(statsArray.map(function (stats, index) {
|
||||
return getMetadata(dir, path.join(file, files[index]), stats, maximumDepth - 1)
|
||||
return getMetadataRecursive(dir, path.join(file, files[index]), stats, maximumDepth - 1)
|
||||
}))
|
||||
})
|
||||
)
|
||||
|
@ -28,7 +29,19 @@ function formatTime(time) {
|
|||
return new Date(time).toISOString()
|
||||
}
|
||||
|
||||
function getMetadata(dir, file, stats, maximumDepth) {
|
||||
function getIntegrity(file) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(file, function (error, data) {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(SRIToolbox.generate({ algorithms: [ 'sha384' ] }, data))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getMetadataRecursive(dir, file, stats, maximumDepth) {
|
||||
const metadata = {
|
||||
lastModified: formatTime(stats.mtime),
|
||||
contentType: getContentType(file),
|
||||
|
@ -37,6 +50,13 @@ function getMetadata(dir, file, stats, maximumDepth) {
|
|||
type: getFileType(stats)
|
||||
}
|
||||
|
||||
if (stats.isFile()) {
|
||||
return getIntegrity(path.join(dir, file)).then(function (integrity) {
|
||||
metadata.integrity = integrity
|
||||
return metadata
|
||||
})
|
||||
}
|
||||
|
||||
if (!stats.isDirectory() || maximumDepth === 0)
|
||||
return Promise.resolve(metadata)
|
||||
|
||||
|
@ -46,12 +66,12 @@ function getMetadata(dir, file, stats, maximumDepth) {
|
|||
})
|
||||
}
|
||||
|
||||
function generateMetadata(baseDir, path, stats, maximumDepth, callback) {
|
||||
return getMetadata(baseDir, path, stats, maximumDepth).then(function (metadata) {
|
||||
function getMetadata(baseDir, path, stats, maximumDepth, callback) {
|
||||
getMetadataRecursive(baseDir, path, stats, maximumDepth).then(function (metadata) {
|
||||
callback(null, metadata)
|
||||
}, callback)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: generateMetadata
|
||||
get: getMetadata
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const qs = require('querystring')
|
||||
const etag = require('etag')
|
||||
const Metadata = require('./MetadataUtils')
|
||||
const { generateDirectoryIndexHTML } = require('./IndexUtils')
|
||||
const { getContentType } = require('./FileUtils')
|
||||
|
||||
|
@ -10,11 +10,6 @@ const { getContentType } = require('./FileUtils')
|
|||
*/
|
||||
const AutoIndex = !process.env.DISABLE_INDEX
|
||||
|
||||
/**
|
||||
* Maximum recursion depth for ?meta listings.
|
||||
*/
|
||||
const MaximumDepth = 128
|
||||
|
||||
function sendFile(res, file, stats) {
|
||||
let contentType = getContentType(file)
|
||||
|
||||
|
@ -41,20 +36,12 @@ function sendFile(res, file, stats) {
|
|||
* Send the file, JSON metadata, or HTML directory listing.
|
||||
*/
|
||||
function serveFile(req, res, next) {
|
||||
// TODO: remove support for "json" query param
|
||||
if (req.query.meta != null || req.query.json != null) {
|
||||
Metadata.get(req.packageDir, req.file, req.stats, MaximumDepth, function (error, metadata) {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
res.status(500).type('text').send(`Cannot generate JSON metadata for ${req.packageSpec}${req.filename}`)
|
||||
} else {
|
||||
// Cache metadata for 1 year.
|
||||
res.set({
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
'Cache-Tag': 'meta'
|
||||
}).send(metadata)
|
||||
}
|
||||
})
|
||||
// Preserve support for ?meta and ?json for backwards compat.
|
||||
delete req.query.meta
|
||||
delete req.query.json
|
||||
const search = qs.stringify(req.query)
|
||||
res.status(301).redirect(`/_meta${req.pathname}${search}`)
|
||||
} else if (req.stats.isFile()) {
|
||||
// Cache files for 1 year.
|
||||
res.set({
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
const Metadata = require('./MetadataUtils')
|
||||
|
||||
/**
|
||||
* Maximum recursion depth for ?meta listings.
|
||||
*/
|
||||
const MaximumDepth = 128
|
||||
|
||||
function serveMetadata(req, res) {
|
||||
Metadata.get(req.packageDir, req.file, 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}`)
|
||||
} else {
|
||||
// Cache metadata for 1 year.
|
||||
res.set({
|
||||
'Cache-Control': 'public, max-age=31536000',
|
||||
'Cache-Tag': 'meta'
|
||||
}).send(metadata)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = serveMetadata
|
|
@ -4929,6 +4929,10 @@ sprintf-js@~1.0.2:
|
|||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
||||
sri-toolbox@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c"
|
||||
|
|
Loading…
Reference in New Issue