UNPKG

@cocalc/hub

Version:
113 lines (107 loc) 4.73 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = require("path"); const logger_1 = require("@cocalc/hub/logger"); const misc_1 = require("@cocalc/util/misc"); const pool_1 = __importDefault(require("@cocalc/database/pool")); const url_1 = require("url"); const winston = (0, logger_1.getLogger)("share-redirect"); // Redirects for backward compatibility with the old share server. const sha1re = new RegExp(/\b([a-f0-9]{40})\b/); function redirect(basePath) { const users = (0, path_1.join)(basePath, "users/"); const accounts = (0, path_1.join)(basePath, "accounts/"); winston.info("creating share server legacy redirect", { users, accounts }); return async (req, res, next) => { /* The mapping: /users --> /accounts /{share sha1 hash}/the/path --> /public_paths/{share sha1 hash}/path /{share sha1 hash}/the/path?viewer='share' --> /public_paths/{share sha1 hash}/path /{share sha1 hash}/the/path?viewer='embed' --> /public_paths/embed/{share sha1 hash}/path /{share sha1 hash}/the/path?viewer='raw' --> /raw/{share sha1 hash}/the/path /{share sha1 hash}/the/path?viewer='download' --> /download/{share sha1 hash}/the/path Note that raw and download need the whole path in order to determine the MIME type of the file being downloaded in general. This is because "the/path" could be a *single* filename (when a user shares a single file, instead of a folder), in which case "/path" is empty. (This is like gists versus github repos.) Clarifying the first redirect: /{share sha1 hash}/the/full/share/path/in/the/share.ipynb --> /public_paths/{share sha1 hash}/in/the/share.pynb So we must consult the database to do this redirect, except in the raw/download cases. */ const { url } = req; // winston.http("redirect %s", url); if (url.startsWith(users)) { res.redirect(301, accounts + url.slice(users.length)); return; } // Next check if url starts with basePath/{sha1hash}/ // We first do quick check for a slash in the position // it would be in if it were basePath/{sha1hash}/. // No valid new url has a slash there, so there is a very // fast check, so that the slower regexp check below only // happsens when a redirect is very likely. const i = basePath.length + 41; if (url[i] != "/") { next(); return; } const m = url.match(sha1re); if (m == null || m.index != basePath.length + 1) { next(); return; } const sha1hash = m[0]; // the 'http://' is so it is an actual url; we don't use it. const u = new url_1.URL("http://" + url); let page = u.searchParams.get("viewer") ?? "public_paths"; if (!page || page == "share") { page = "public_paths"; } else if (page == "embed") { page = "public_paths/embed"; } const [fullPath] = (0, misc_1.splitFirst)(url.slice(basePath.length + 42), "?"); let path; try { path = page == "raw" || page == "download" ? fullPath : await pathInShare(sha1hash, fullPath); } catch (_err) { winston.http("error getting pathInShare", _err); next(); return; } // winston.http(`got path="${path}"`); const dest = (0, path_1.join)(basePath, `${page}/${sha1hash}${path ? "/" + path : ""}`); winston.http("/sha1 share redirect ", url, " --> ", dest); res.redirect(301, dest); }; } exports.default = redirect; // cache forever if we grab from db, since these never change const sha1ToPath = {}; async function pathInShare(sha1hash, fullPath) { fullPath = decodeURI(fullPath); // winston.debug("pathInShare", { sha1hash, fullPath }); let sharePath; if (sha1ToPath[sha1hash] != null) { sharePath = sha1ToPath[sha1hash]; } else { const pool = (0, pool_1.default)(); const { rows } = await pool.query("SELECT path FROM public_paths WHERE id=$1", [sha1hash]); if (rows.length == 0) { throw Error("no such public path"); } sharePath = rows[0].path; sha1ToPath[sha1hash] = sharePath; } return encodeURI(fullPath.slice(sharePath.length + 1)); } //# sourceMappingURL=share-redirect.js.map