mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-15 23:25:27 +02:00
fix: enforce content policies using original file types
This commit is contained in:
@@ -343,7 +343,7 @@ export default class AnonymizedFile {
|
|||||||
|
|
||||||
async anonymizedContent() {
|
async anonymizedContent() {
|
||||||
const anonymizer = this.repository.generateAnonymizeTransformer(
|
const anonymizer = this.repository.generateAnonymizeTransformer(
|
||||||
this.anonymizedPath
|
await this.originalPath()
|
||||||
);
|
);
|
||||||
if (!config.STREAMER_ENTRYPOINT) {
|
if (!config.STREAMER_ENTRYPOINT) {
|
||||||
// collect the content locally
|
// collect the content locally
|
||||||
@@ -385,7 +385,7 @@ export default class AnonymizedFile {
|
|||||||
|
|
||||||
async send(res: Response): Promise<void> {
|
async send(res: Response): Promise<void> {
|
||||||
const anonymizer = this.repository.generateAnonymizeTransformer(
|
const anonymizer = this.repository.generateAnonymizeTransformer(
|
||||||
this.anonymizedPath
|
await this.originalPath()
|
||||||
);
|
);
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
return new Promise<void>(async (resolve, reject) => {
|
return new Promise<void>(async (resolve, reject) => {
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export async function streamAnonymizedZip(
|
|||||||
entry.path.substring(entry.path.indexOf("/") + 1),
|
entry.path.substring(entry.path.indexOf("/") + 1),
|
||||||
compiledTerms
|
compiledTerms
|
||||||
);
|
);
|
||||||
if (!isEntryAllowed(fileName, opt.contentOptions)) {
|
if (!isEntryAllowed(entry.path, opt.contentOptions)) {
|
||||||
entry.autodrain();
|
entry.autodrain();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,7 @@ export async function streamAnonymizedZip(
|
|||||||
// isText=false for every file, so the zip ships unanonymized.
|
// isText=false for every file, so the zip ships unanonymized.
|
||||||
const anonymizer = new AnonymizeTransformer({
|
const anonymizer = new AnonymizeTransformer({
|
||||||
...opt.anonymizerOptions,
|
...opt.anonymizerOptions,
|
||||||
filePath: fileName,
|
filePath: entry.path,
|
||||||
});
|
});
|
||||||
const st = entry.pipe(anonymizer);
|
const st = entry.pipe(anonymizer);
|
||||||
archive.append(st, { name: fileName });
|
archive.append(st, { name: fileName });
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ router.get(
|
|||||||
repository: repo,
|
repository: repo,
|
||||||
anonymizedPath,
|
anonymizedPath,
|
||||||
});
|
});
|
||||||
|
const originalPath = await f.originalPath();
|
||||||
if (!f.isFileSupported()) {
|
if (!f.isFileSupported()) {
|
||||||
throw new AnonymousError("file_not_supported", {
|
throw new AnonymousError("file_not_supported", {
|
||||||
httpStatus: 403,
|
httpStatus: 403,
|
||||||
@@ -115,7 +116,7 @@ router.get(
|
|||||||
res.attachment(
|
res.attachment(
|
||||||
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
|
anonymizedPath.substring(anonymizedPath.lastIndexOf("/") + 1)
|
||||||
);
|
);
|
||||||
} else if (isScriptableDocument(anonymizedPath)) {
|
} else if (isScriptableDocument(originalPath) || isScriptableDocument(anonymizedPath)) {
|
||||||
// A repository's own .html/.svg is untrusted content served from our
|
// A repository's own .html/.svg is untrusted content served from our
|
||||||
// origin: opening it renders it as a document, and any script in it
|
// origin: opening it renders it as a document, and any script in it
|
||||||
// would run as the site itself (session cookie, same-origin fetches
|
// would run as the site itself (session cookie, same-origin fetches
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ async function webView(req: express.Request, res: express.Response) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await f.originalPath();
|
||||||
if (!f.isFileSupported()) {
|
if (!f.isFileSupported()) {
|
||||||
throw new AnonymousError("file_not_supported", {
|
throw new AnonymousError("file_not_supported", {
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
|
|||||||
@@ -119,6 +119,34 @@ describe("production regressions", function () {
|
|||||||
throw new Error("expected rejection");
|
throw new Error("expected rejection");
|
||||||
} catch (error) { expect(error.message).to.equal("token_expired"); }
|
} catch (error) { expect(error.message).to.equal("token_expired"); }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function response() {
|
||||||
|
return { headers: {}, header(key, value) { this.headers[key] = value; return this; },
|
||||||
|
contentType() { return this; }, status(value) { this.statusCode = value; return this; }, end() {}, send() {} };
|
||||||
|
}
|
||||||
|
function fileRoute(originalName) {
|
||||||
|
const File = require("../src/core/AnonymizedFile").default;
|
||||||
|
const utils = require("../src/server/routes/route-utils");
|
||||||
|
const repo = { options: { pdf: false, image: false, terms: [] }, model: { source: { commit: "commit-1" }, options: {} }, isReady: async () => true, countView: async () => {} };
|
||||||
|
stub(utils, "getRepo", async () => repo);
|
||||||
|
stub(File.prototype, "originalPath", async function () { this._file = { name: originalName, path: "" }; return originalName; });
|
||||||
|
stub(File.prototype, "sha", async () => "sha");
|
||||||
|
stub(File.prototype, "send", async () => {});
|
||||||
|
const handler = require("../src/server/routes/file").default.stack[0].route.stack[0].handle;
|
||||||
|
return { repo, handler, req: { url: "/repo/file/page.txt?v=old", protocol: "https", hostname: "host", params: { repoId: "repo" }, query: { v: "old" }, headers: {} } };
|
||||||
|
}
|
||||||
|
it("gates PDFs using their original extension", async function () {
|
||||||
|
const { handler, req } = fileRoute("report.pdf");
|
||||||
|
let failure;
|
||||||
|
stub(require("../src/server/routes/route-utils"), "handleError", error => { failure = error; });
|
||||||
|
await handler(req, response());
|
||||||
|
expect(failure.message).to.equal("file_not_supported");
|
||||||
|
});
|
||||||
|
it("sandboxes renamed HTML documents", async function () {
|
||||||
|
const { handler, req } = fileRoute("page.html");
|
||||||
|
const first = response(); await handler(req, first);
|
||||||
|
expect(first.headers["Content-Security-Policy"]).to.include("sandbox");
|
||||||
|
});
|
||||||
it("omits an upstream length when later text is rewritten", async function () {
|
it("omits an upstream length when later text is rewritten", async function () {
|
||||||
const File = require("../src/core/AnonymizedFile").default;
|
const File = require("../src/core/AnonymizedFile").default;
|
||||||
stub(config, "STREAMER_ENTRYPOINT", "");
|
stub(config, "STREAMER_ENTRYPOINT", "");
|
||||||
|
|||||||
Reference in New Issue
Block a user