"use strict";
/*
This handles request to share/raw/[sha1]/[relative path].

It confirms that the request is valid (so the content is
actually currently publicly shared) then sends the result.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.staticHandler = void 0;
const path_1 = require("path");
const express_1 = require("express");
const serve_index_1 = __importDefault(require("serve-index"));
const util_1 = require("./util");
const path_to_files_1 = require("./path-to-files");
const lru_cache_1 = __importDefault(require("lru-cache"));
const ms_1 = __importDefault(require("ms"));
const MAX_AGE = Math.round((0, ms_1.default)("15 minutes") / 1000);
async function handle(options) {
    try {
        await handleRequest(options);
    }
    catch (err) {
        // some other error
        options.res.send(`Error: ${err}`);
    }
}
exports.default = handle;
async function handleRequest(opts) {
    const { id, // id of a public_path
    path: pathEncoded, // full path in the project to requested file or directory
    req, res, download, next, } = opts;
    res.setHeader("Cache-Control", `public, max-age=${MAX_AGE}`);
    if (!(0, util_1.isSha1Hash)(id)) {
        throw Error(`id=${id} is not a sha1 hash`);
    }
    // store the URI decoded string from pathEncoded in path
    // BUGFIX: https://github.com/sagemathinc/cocalc/issues/5928
    // This does not work with file names containing a percent sign, because next.js itself does decode the path as well.
    const path = decodeURIComponent(pathEncoded);
    // the above must come before this check (since dots could be somehow encoded)
    if (path.includes("..")) {
        throw Error(`path (="${path}") must not include ".."`);
    }
    let { fsPath, projectPath } = await (0, path_to_files_1.pathFromID)(id);
    if (!path.startsWith(projectPath)) {
        // The projectPath absolutely must be an initial segment of the requested path.
        // We do NOT just use a relative path *inside* the share, because the share might be a file itself
        // and then the MIME type wouldn't be a function of the URL.
        throw Error(`path (="${path}") must start with "${projectPath}"`);
    }
    let url = path.slice(projectPath.length);
    const target = (0, path_1.join)(fsPath, url);
    const ext = (0, util_1.getExtension)(target);
    if (download || ext == "html" || ext == "svg") {
        // NOTE: We *always* download .html, since it is far too dangerous to render
        // an arbitrary html file from our domain.
        res.download(target, next);
        return;
    }
    if (!url) {
        const i = fsPath.lastIndexOf("/");
        if (i == -1) {
            // This can't actually happen, since fsPath is an absolute filesystem path, hence starts with /
            throw Error(`invalid fsPath=${fsPath}`);
        }
        url = fsPath.slice(i);
        fsPath = fsPath.slice(0, i);
    }
    req.url = url;
    staticHandler(fsPath, req, res, next);
}
function staticHandler(fsPath, req, res, next) {
    //console.log("staticHandler", { fsPath, url: req.url });
    const handler = getStaticFileHandler(fsPath);
    handler(req, res, () => {
        // Static handler didn't work, so try the directory listing handler.
        //console.log("directoryHandler", { fsPath, url: req.url });
        const handler = getDirectoryHandler(fsPath);
        handler(req, res, next);
    });
}
exports.staticHandler = staticHandler;
const staticFileCache = new lru_cache_1.default({ max: 200 });
function getStaticFileHandler(path) {
    if (staticFileCache.has(path)) {
        return staticFileCache.get(path);
    }
    const handler = (0, express_1.static)(path);
    staticFileCache.set(path, handler);
    return handler;
}
const directoryCache = new lru_cache_1.default({ max: 200 });
function getDirectoryHandler(path) {
    if (directoryCache.has(path)) {
        return directoryCache.get(path);
    }
    const handler = (0, serve_index_1.default)(path, { icons: true, view: "details" });
    directoryCache.set(path, handler);
    return handler;
}
//# sourceMappingURL=handle-raw.js.map