From 231b2fe0c8428c03580d140bc4a6507dfe4e5b53 Mon Sep 17 00:00:00 2001 From: tdurieux Date: Mon, 24 Oct 2022 08:34:53 +0200 Subject: [PATCH] feat(#137): adds support for md rendering in webview --- package-lock.json | 30 ++++++++++++++++++++++++++++++ package.json | 2 ++ public/script/app.js | 2 +- src/AnonymizedFile.ts | 35 ++++++++++++++++++++++++----------- src/anonymize-utils.ts | 10 ++++++++++ src/routes/webview.ts | 9 ++++++++- 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66e0f5b..d1c7b85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "express-slow-down": "^1.5.0", "got": "^11.8.5", "istextorbinary": "^6.0.0", + "marked": "^4.1.1", "mime-types": "^2.1.35", "mongoose": "^6.5.4", "node-schedule": "^2.1.0", @@ -47,6 +48,7 @@ "@types/express-session": "^1.17.5", "@types/express-slow-down": "^1.3.2", "@types/got": "^9.6.12", + "@types/marked": "^4.0.7", "@types/mime-types": "^2.1.0", "@types/parse-github-url": "^1.0.0", "@types/passport": "^1.0.10", @@ -934,6 +936,12 @@ "@types/node": "*" } }, + "node_modules/@types/marked": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", + "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==", + "dev": true + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -3611,6 +3619,17 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/marked": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", + "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6143,6 +6162,12 @@ "@types/node": "*" } }, + "@types/marked": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", + "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==", + "dev": true + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -8160,6 +8185,11 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "marked": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.1.1.tgz", + "integrity": "sha512-0cNMnTcUJPxbA6uWmCmjWz4NJRe/0Xfk2NhXCUHjew9qJzFN20krFnsUe7QynwqOwa5m1fZ4UDg0ycKFVC0ccw==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", diff --git a/package.json b/package.json index 32cae62..6c654c3 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "express-slow-down": "^1.5.0", "got": "^11.8.5", "istextorbinary": "^6.0.0", + "marked": "^4.1.1", "mime-types": "^2.1.35", "mongoose": "^6.5.4", "node-schedule": "^2.1.0", @@ -62,6 +63,7 @@ "@types/express-session": "^1.17.5", "@types/express-slow-down": "^1.3.2", "@types/got": "^9.6.12", + "@types/marked": "^4.0.7", "@types/mime-types": "^2.1.0", "@types/parse-github-url": "^1.0.0", "@types/passport": "^1.0.10", diff --git a/public/script/app.js b/public/script/app.js index 7da80b8..ba4367f 100644 --- a/public/script/app.js +++ b/public/script/app.js @@ -1267,7 +1267,7 @@ angular ts: "typescript", }; const textFiles = ["license", "txt"]; - const imageFiles = ["png", "jpg", "jpeg", "gif", "svg"]; + const imageFiles = ["png", "jpg", "jpeg", "gif", "svg", "ico", "bmp", "tiff", "tif", "webp", "avif", "heif", "heic"]; $scope.$on("$routeUpdate", function (event, current) { if (($routeParams.path || "") == $scope.filePath) { diff --git a/src/AnonymizedFile.ts b/src/AnonymizedFile.ts index 8990988..6850af5 100644 --- a/src/AnonymizedFile.ts +++ b/src/AnonymizedFile.ts @@ -137,22 +137,35 @@ export default class AnonymizedFile { return this._originalPath; } - - async isFileSupported() { + async extension() { const filename = basename(await this.originalPath()); const extensions = filename.split(".").reverse(); - const extension = extensions[0].toLowerCase(); + return extensions[0].toLowerCase(); + } + async isImage(): Promise { + const extension = await this.extension(); + return [ + "png", + "jpg", + "jpeg", + "gif", + "svg", + "ico", + "bmp", + "tiff", + "tif", + "webp", + "avif", + "heif", + "heic", + ].includes(extension); + } + async isFileSupported() { + const extension = await this.extension(); if (!this.repository.options.pdf && extension == "pdf") { return false; } - if ( - !this.repository.options.image && - (extension == "png" || - extension == "ico" || - extension == "jpg" || - extension == "jpeg" || - extension == "gif") - ) { + if (!this.repository.options.image && (await this.isImage())) { return false; } return true; diff --git a/src/anonymize-utils.ts b/src/anonymize-utils.ts index 40d4137..46d58fb 100644 --- a/src/anonymize-utils.ts +++ b/src/anonymize-utils.ts @@ -4,10 +4,20 @@ import GitHubBase from "./source/GitHubBase"; import { isText } from "istextorbinary"; import { basename } from "path"; import { Transform } from "stream"; +import { Readable } from "stream"; const urlRegex = /?/g; +export function streamToString(stream: Readable): Promise { + const chunks = []; + return new Promise((resolve, reject) => { + stream.on("data", (chunk) => chunks.push(Buffer.from(chunk))); + stream.on("error", (err) => reject(err)); + stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8"))); + }); +} + export function isTextFile(filePath: string, content: Buffer) { const filename = basename(filePath); const extensions = filename.split(".").reverse(); diff --git a/src/routes/webview.ts b/src/routes/webview.ts index 7a11cb7..21d5462 100644 --- a/src/routes/webview.ts +++ b/src/routes/webview.ts @@ -5,6 +5,8 @@ import AnonymizedFile from "../AnonymizedFile"; import GitHubDownload from "../source/GitHubDownload"; import AnonymousError from "../AnonymousError"; import { TreeElement } from "../types"; +import * as marked from "marked"; +import { anonymizeContent, streamToString } from "../anonymize-utils"; const router = express.Router(); @@ -99,7 +101,12 @@ async function webView(req: express.Request, res: express.Response) { object: f, }); } - f.send(res); + if ((await f.extension()) == "md") { + const content = await streamToString(await f.anonymizedContent()); + res.send(marked.marked(content)); + } else { + f.send(res); + } } catch (error) { handleError(error, res, req); }