mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-05-15 22:48:00 +02:00
refactor: route anonymize preview through the backend
The form's live README/PR preview was running its own copy of ContentAnonimizer in the browser. The two implementations had been drifting — recent fixes for word boundaries (#175/#249), accent matching (#280), custom replacements (#285), and the diacritic-stripped variants only landed on the server. Reviewers saw one anonymization; authors composing the form saw another. Add POST /api/anonymize-preview that takes a snippet (or a batch) plus the user's options and runs them through the same ContentAnonimizer the file route uses. Replace the client-side anonymizeReadme() body with a debounced call to that endpoint. The PR view's anonymizePrContent() runs as a synchronous template expression, so it now reads from a {original -> anonymized} cache that's refreshed in the background whenever the PR details, terms, or options change. Single-flight + debounce keep the form responsive; an in-flight request is dropped on the next change.
This commit is contained in:
@@ -161,6 +161,7 @@ export default async function start() {
|
||||
apiRouter.use("/repo", speedLimiter, router.repositoryPrivate);
|
||||
apiRouter.use("/pr", speedLimiter, router.pullRequestPublic);
|
||||
apiRouter.use("/pr", speedLimiter, router.pullRequestPrivate);
|
||||
apiRouter.use("/anonymize-preview", speedLimiter, router.anonymizePreview);
|
||||
|
||||
apiRouter.get("/message", async (_, res) => {
|
||||
if (existsSync("./message.txt")) {
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import * as express from "express";
|
||||
import { ContentAnonimizer } from "../../core/anonymize-utils";
|
||||
import { handleError } from "./route-utils";
|
||||
import { ensureAuthenticated } from "./connection";
|
||||
|
||||
const router = express.Router();
|
||||
router.use(ensureAuthenticated);
|
||||
|
||||
// Anonymize one or more snippets of content with the same logic the backend
|
||||
// uses on real anonymized files. The form's preview was running a duplicate
|
||||
// of ContentAnonimizer in the browser, which drifted from the backend (missed
|
||||
// fixes for word boundaries, accent matching, custom replacements, etc.).
|
||||
// Routing the preview through this endpoint keeps the two in lockstep.
|
||||
//
|
||||
// Accepts either { content: string } (single) or { contents: string[] }
|
||||
// (batch) so the PR preview can scrub many fields in one round trip.
|
||||
router.post("/", async (req: express.Request, res: express.Response) => {
|
||||
try {
|
||||
const body: {
|
||||
content?: unknown;
|
||||
contents?: unknown;
|
||||
options?: {
|
||||
terms?: string[];
|
||||
image?: boolean;
|
||||
link?: boolean;
|
||||
repoName?: string;
|
||||
branchName?: string;
|
||||
repoId?: string;
|
||||
};
|
||||
} = req.body || {};
|
||||
|
||||
let inputs: string[];
|
||||
let single = false;
|
||||
if (typeof body.content === "string") {
|
||||
inputs = [body.content];
|
||||
single = true;
|
||||
} else if (
|
||||
Array.isArray(body.contents) &&
|
||||
body.contents.every((c) => typeof c === "string")
|
||||
) {
|
||||
inputs = body.contents as string[];
|
||||
} else {
|
||||
return res.status(400).json({ error: "missing_content" });
|
||||
}
|
||||
|
||||
const opt = body.options || {};
|
||||
// Construct one anonymizer per snippet so the wasAnonymized flag is per
|
||||
// input. ContentAnonimizer is cheap to instantiate.
|
||||
const outputs = inputs.map((content) => {
|
||||
const a = new ContentAnonimizer({
|
||||
terms: Array.isArray(opt.terms) ? opt.terms : [],
|
||||
image: opt.image,
|
||||
link: opt.link,
|
||||
repoName: opt.repoName,
|
||||
branchName: opt.branchName,
|
||||
repoId: opt.repoId,
|
||||
});
|
||||
return a.anonymize(content);
|
||||
});
|
||||
|
||||
if (single) {
|
||||
return res.json({ content: outputs[0] });
|
||||
}
|
||||
res.json({ contents: outputs });
|
||||
} catch (error) {
|
||||
handleError(error, res, req);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -8,6 +8,7 @@ import webview from "./webview";
|
||||
import user from "./user";
|
||||
import option from "./option";
|
||||
import admin from "./admin";
|
||||
import anonymizePreview from "./anonymize-preview";
|
||||
|
||||
export default {
|
||||
pullRequestPrivate,
|
||||
@@ -20,4 +21,5 @@ export default {
|
||||
option,
|
||||
conference,
|
||||
admin,
|
||||
anonymizePreview,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user