improved archive handler

This commit is contained in:
daniel31x13 2024-06-29 17:18:38 -04:00
parent d66c784d3f
commit 644b827669
8 changed files with 46 additions and 49 deletions

View File

@ -10,8 +10,8 @@ export default function Announcement({ toggleAnnouncementBar }: Props) {
const announcementId = localStorage.getItem("announcementId"); const announcementId = localStorage.getItem("announcementId");
return ( return (
<div className="fixed left-0 right-0 bottom-20 sm:bottom-10 w-full p-5 z-30"> <div className="fixed mx-auto bottom-20 sm:bottom-10 w-full pointer-events-none p-5 z-30">
<div className="mx-auto w-full p-2 flex justify-between gap-2 items-center border border-primary shadow-xl rounded-xl bg-base-300 backdrop-blur-sm bg-opacity-80 max-w-md"> <div className="mx-auto pointer-events-auto p-2 flex justify-between gap-2 items-center border border-primary shadow-xl rounded-xl bg-base-300 backdrop-blur-sm bg-opacity-80 max-w-md">
<i className="bi-stars text-2xl text-yellow-600 dark:text-yellow-500"></i> <i className="bi-stars text-2xl text-yellow-600 dark:text-yellow-500"></i>
<p className="w-4/5 text-center text-sm sm:text-base"> <p className="w-4/5 text-center text-sm sm:text-base">
<Trans <Trans

View File

@ -2,7 +2,7 @@ import { LaunchOptions, chromium, devices } from "playwright";
import { prisma } from "./db"; import { prisma } from "./db";
import sendToWayback from "./preservationScheme/sendToWayback"; import sendToWayback from "./preservationScheme/sendToWayback";
import { Collection, Link, User } from "@prisma/client"; import { Collection, Link, User } from "@prisma/client";
import validateUrlSize from "./validateUrlSize"; import fetchHeaders from "./fetchHeaders";
import createFolder from "./storage/createFolder"; import createFolder from "./storage/createFolder";
import { removeFiles } from "./manageLinkFiles"; import { removeFiles } from "./manageLinkFiles";
import handleMonolith from "./preservationScheme/handleMonolith"; import handleMonolith from "./preservationScheme/handleMonolith";
@ -65,17 +65,9 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
(async () => { (async () => {
const user = link.collection?.owner; const user = link.collection?.owner;
const validatedUrl = link.url const header = link.url ? await fetchHeaders(link.url) : undefined;
? await validateUrlSize(link.url)
: undefined;
if ( const contentType = header?.get("content-type");
validatedUrl === null &&
process.env.IGNORE_URL_SIZE_LIMIT !== "true"
)
throw "Something went wrong while retrieving the file size.";
const contentType = validatedUrl?.get("content-type");
let linkType = "url"; let linkType = "url";
let imageExtension = "png"; let imageExtension = "png";

View File

@ -1,8 +1,7 @@
import { prisma } from "@/lib/api/db"; import { prisma } from "@/lib/api/db";
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global"; import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
import getTitle from "@/lib/shared/getTitle"; import fetchTitleAndHeaders from "@/lib/shared/fetchTitleAndHeaders";
import createFolder from "@/lib/api/storage/createFolder"; import createFolder from "@/lib/api/storage/createFolder";
import validateUrlSize from "../../validateUrlSize";
import setLinkCollection from "../../setLinkCollection"; import setLinkCollection from "../../setLinkCollection";
const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000; const MAX_LINKS_PER_USER = Number(process.env.MAX_LINKS_PER_USER) || 30000;
@ -70,17 +69,12 @@ export default async function postLink(
status: 400, status: 400,
}; };
const title = const { title, headers } = await fetchTitleAndHeaders(link.url || "");
!(link.name && link.name !== "") && link.url
? await getTitle(link.url)
: "";
const name = const name =
link.name && link.name !== "" ? link.name : link.url ? title : ""; link.name && link.name !== "" ? link.name : link.url ? title : "";
const validatedUrl = link.url ? await validateUrlSize(link.url) : undefined; const contentType = headers?.get("content-type");
const contentType = validatedUrl?.get("content-type");
let linkType = "url"; let linkType = "url";
let imageExtension = "png"; let imageExtension = "png";

View File

@ -2,7 +2,7 @@ import fetch from "node-fetch";
import https from "https"; import https from "https";
import { SocksProxyAgent } from "socks-proxy-agent"; import { SocksProxyAgent } from "socks-proxy-agent";
export default async function validateUrlSize(url: string) { export default async function fetchHeaders(url: string) {
if (process.env.IGNORE_URL_SIZE_LIMIT === "true") return null; if (process.env.IGNORE_URL_SIZE_LIMIT === "true") return null;
try { try {
@ -29,13 +29,17 @@ export default async function validateUrlSize(url: string) {
}; };
} }
const response = await fetch(url, fetchOpts); const responsePromise = fetch(url, fetchOpts);
const totalSizeMB = const timeoutPromise = new Promise((_, reject) => {
Number(response.headers.get("content-length")) / Math.pow(1024, 2); setTimeout(() => {
if (totalSizeMB > Number(process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10)) reject(new Error("Fetch header timeout"));
return null; }, 10 * 1000); // Stop after 10 seconds
else return response.headers; });
const response = await Promise.race([responsePromise, timeoutPromise]);
return (response as Response)?.headers || null;
} catch (err) { } catch (err) {
console.log(err); console.log(err);
return null; return null;

View File

@ -1,6 +1,7 @@
import { Link } from "@prisma/client"; import { Link } from "@prisma/client";
import { prisma } from "../db"; import { prisma } from "../db";
import createFile from "../storage/createFile"; import createFile from "../storage/createFile";
import generatePreview from "../generatePreview";
const imageHandler = async ({ url, id }: Link, extension: string) => { const imageHandler = async ({ url, id }: Link, extension: string) => {
const image = await fetch(url as string).then((res) => res.blob()); const image = await fetch(url as string).then((res) => res.blob());
@ -18,6 +19,8 @@ const imageHandler = async ({ url, id }: Link, extension: string) => {
}); });
if (linkExists) { if (linkExists) {
await generatePreview(buffer, linkExists.collectionId, id);
await createFile({ await createFile({
data: buffer, data: buffer,
filePath: `archives/${linkExists.collectionId}/${id}.${extension}`, filePath: `archives/${linkExists.collectionId}/${id}.${extension}`,

View File

@ -2,7 +2,7 @@ import fetch from "node-fetch";
import https from "https"; import https from "https";
import { SocksProxyAgent } from "socks-proxy-agent"; import { SocksProxyAgent } from "socks-proxy-agent";
export default async function getTitle(url: string) { export default async function fetchTitleAndHeaders(url: string) {
try { try {
const httpsAgent = new https.Agent({ const httpsAgent = new https.Agent({
rejectUnauthorized: rejectUnauthorized:
@ -41,12 +41,16 @@ export default async function getTitle(url: string) {
// regular expression to find the <title> tag // regular expression to find the <title> tag
let match = text.match(/<title.*>([^<]*)<\/title>/); let match = text.match(/<title.*>([^<]*)<\/title>/);
if (match) return match[1];
else return ""; const title = match[1] || "";
const headers = (response as Response)?.headers || null;
return { title, headers };
} else { } else {
return ""; return { title: "", headers: null };
} }
} catch (err) { } catch (err) {
console.log(err); console.log(err);
return { title: "", headers: null };
} }
} }

View File

@ -60,7 +60,7 @@
"next-i18next": "^15.3.0", "next-i18next": "^15.3.0",
"node-fetch": "^2.7.0", "node-fetch": "^2.7.0",
"nodemailer": "^6.9.3", "nodemailer": "^6.9.3",
"playwright": "^1.43.1", "playwright": "^1.45.0",
"react": "18.2.0", "react": "18.2.0",
"react-colorful": "^5.6.1", "react-colorful": "^5.6.1",
"react-dom": "18.2.0", "react-dom": "18.2.0",
@ -77,7 +77,7 @@
"zustand": "^4.3.8" "zustand": "^4.3.8"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.43.1", "@playwright/test": "^1.45.0",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/dompurify": "^3.0.4", "@types/dompurify": "^3.0.4",
"@types/jsdom": "^21.1.3", "@types/jsdom": "^21.1.3",

View File

@ -1293,12 +1293,12 @@
tiny-glob "^0.2.9" tiny-glob "^0.2.9"
tslib "^2.4.0" tslib "^2.4.0"
"@playwright/test@^1.43.1": "@playwright/test@^1.45.0":
version "1.43.1" version "1.45.0"
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.43.1.tgz#16728a59eb8ce0f60472f98d8886d6cab0fa3e42" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.45.0.tgz#790a66165a46466c0d7099dd260881802f5aba7e"
integrity sha512-HgtQzFgNEEo4TE22K/X7sYTYNqEMMTZmFS8kTq6m8hXj+m1D8TgwgIbumHddJa9h4yl4GkKb8/bgAl2+g7eDgA== integrity sha512-TVYsfMlGAaxeUllNkywbwek67Ncf8FRGn8ZlRdO291OL3NjG9oMbfVhyP82HQF0CZLMrYsvesqoUekxdWuF9Qw==
dependencies: dependencies:
playwright "1.43.1" playwright "1.45.0"
"@prisma/client@^4.16.2": "@prisma/client@^4.16.2":
version "4.16.2" version "4.16.2"
@ -5005,17 +5005,17 @@ pixelmatch@^4.0.2:
dependencies: dependencies:
pngjs "^3.0.0" pngjs "^3.0.0"
playwright-core@1.43.1: playwright-core@1.45.0:
version "1.43.1" version "1.45.0"
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.43.1.tgz#0eafef9994c69c02a1a3825a4343e56c99c03b02" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.45.0.tgz#5741a670b7c9060ce06852c0051d84736fb94edc"
integrity sha512-EI36Mto2Vrx6VF7rm708qSnesVQKbxEWvPrfA1IPY6HgczBplDx7ENtx+K2n4kJ41sLLkuGfmb0ZLSSXlDhqPg== integrity sha512-lZmHlFQ0VYSpAs43dRq1/nJ9G/6SiTI7VPqidld9TDefL9tX87bTKExWZZUF5PeRyqtXqd8fQi2qmfIedkwsNQ==
playwright@1.43.1, playwright@^1.43.1: playwright@1.45.0, playwright@^1.45.0:
version "1.43.1" version "1.45.0"
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.43.1.tgz#8ad08984ac66c9ef3d0db035be54dd7ec9f1c7d9" resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.45.0.tgz#400c709c64438690f13705cb9c88ef93089c5c27"
integrity sha512-V7SoH0ai2kNt1Md9E3Gwas5B9m8KR2GVvwZnAI6Pg0m3sh7UvgiYhRrhsziCmqMJNouPckiOhk8T+9bSAK0VIA== integrity sha512-4z3ac3plDfYzGB6r0Q3LF8POPR20Z8D0aXcxbJvmfMgSSq1hkcgvFRXJk9rUq5H/MJ0Ktal869hhOdI/zUTeLA==
dependencies: dependencies:
playwright-core "1.43.1" playwright-core "1.45.0"
optionalDependencies: optionalDependencies:
fsevents "2.3.2" fsevents "2.3.2"