90 lines
2.2 KiB
JavaScript
90 lines
2.2 KiB
JavaScript
const pull = require("pull-stream");
|
|
const cat = require("pull-cat");
|
|
const toPull = require("stream-to-pull-stream");
|
|
const ident = require("pull-identify-filetype");
|
|
const mime = require("mime-types");
|
|
const URL = require("url");
|
|
const debug = require("debug")("server-blobs");
|
|
|
|
const serveBlobs = (sbot) => {
|
|
return (req, res) => {
|
|
const parsed = URL.parse(req.url, true);
|
|
const hash = decodeURIComponent(parsed.pathname.replace("/blob/", ""));
|
|
debug("fetching", hash);
|
|
|
|
waitFor(hash, function (_, has) {
|
|
if (!has) return respond(res, 404, "File not found");
|
|
// optional name override
|
|
if (parsed.query.name) {
|
|
res.setHeader(
|
|
"Content-Disposition",
|
|
"inline; filename=" + encodeURIComponent(parsed.query.name)
|
|
);
|
|
}
|
|
|
|
// serve
|
|
res.setHeader("Content-Security-Policy", BlobCSP());
|
|
|
|
respondSource(res, sbot.blobs.get(hash), false);
|
|
});
|
|
};
|
|
|
|
function waitFor(hash, cb) {
|
|
let finished = false;
|
|
let wrappedCb = (err, result) => {
|
|
if (finished) return;
|
|
finished = true;
|
|
cb(err, result);
|
|
};
|
|
|
|
setTimeout(() => {
|
|
debug("timeout for", hash);
|
|
wrappedCb(null, false);
|
|
}, 5000);
|
|
|
|
sbot.blobs.has(hash, function (err, has) {
|
|
if (err) return wrappedCb(err);
|
|
debug("has is ", has, "for", hash);
|
|
if (has) {
|
|
wrappedCb(null, has);
|
|
} else {
|
|
debug("calling want for", hash);
|
|
sbot.blobs.want(hash, wrappedCb);
|
|
}
|
|
});
|
|
}
|
|
|
|
function respondSource(res, source, wrap) {
|
|
if (wrap) {
|
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
pull(
|
|
cat([
|
|
pull.once("<html><body><script>"),
|
|
source,
|
|
pull.once("</script></body></html>"),
|
|
]),
|
|
toPull.sink(res)
|
|
);
|
|
} else {
|
|
pull(
|
|
source,
|
|
ident(function (type) {
|
|
if (type) res.writeHead(200, { "Content-Type": mime.lookup(type) });
|
|
}),
|
|
toPull.sink(res)
|
|
);
|
|
}
|
|
}
|
|
|
|
function respond(res, status, message) {
|
|
res.writeHead(status);
|
|
res.end(message);
|
|
}
|
|
|
|
function BlobCSP() {
|
|
return "default-src none; sandbox";
|
|
}
|
|
};
|
|
|
|
module.exports = serveBlobs;
|