all
This commit is contained in:
40
Securite/Linkwarden/lib/api/storage/createFile.ts
Normal file
40
Securite/Linkwarden/lib/api/storage/createFile.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { PutObjectCommand, PutObjectCommandInput } from "@aws-sdk/client-s3";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
|
||||
export default async function createFile({
|
||||
filePath,
|
||||
data,
|
||||
isBase64,
|
||||
}: {
|
||||
filePath: string;
|
||||
data: Buffer | string;
|
||||
isBase64?: boolean;
|
||||
}) {
|
||||
if (s3Client) {
|
||||
const bucketParams: PutObjectCommandInput = {
|
||||
Bucket: process.env.SPACES_BUCKET_NAME,
|
||||
Key: filePath,
|
||||
Body: isBase64 ? Buffer.from(data as string, "base64") : data,
|
||||
};
|
||||
|
||||
try {
|
||||
await s3Client.send(new PutObjectCommand(bucketParams));
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log("Error", err);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
|
||||
|
||||
fs.writeFile(creationPath, data, isBase64 ? "base64" : {}, function (err) {
|
||||
if (err) console.log(err);
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
14
Securite/Linkwarden/lib/api/storage/createFolder.ts
Normal file
14
Securite/Linkwarden/lib/api/storage/createFolder.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
|
||||
export default function createFolder({ filePath }: { filePath: string }) {
|
||||
if (s3Client) {
|
||||
// Do nothing, S3 creates directories recursively
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
|
||||
|
||||
fs.mkdirSync(creationPath, { recursive: true });
|
||||
}
|
||||
}
|
37
Securite/Linkwarden/lib/api/storage/moveFile.ts
Normal file
37
Securite/Linkwarden/lib/api/storage/moveFile.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
import removeFile from "./removeFile";
|
||||
|
||||
export default async function moveFile(from: string, to: string) {
|
||||
if (s3Client) {
|
||||
const Bucket = process.env.SPACES_BUCKET_NAME;
|
||||
|
||||
const copyParams = {
|
||||
Bucket: Bucket,
|
||||
CopySource: `/${Bucket}/${from}`,
|
||||
Key: to,
|
||||
};
|
||||
|
||||
try {
|
||||
s3Client.copyObject(copyParams, async (err: any) => {
|
||||
if (err) {
|
||||
console.error("Error copying the object:", err);
|
||||
} else {
|
||||
await removeFile({ filePath: from });
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.log("Error:", err);
|
||||
}
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
|
||||
const directory = (file: string) =>
|
||||
path.join(process.cwd(), storagePath + "/" + file);
|
||||
|
||||
fs.rename(directory(from), directory(to), (err) => {
|
||||
if (err) console.log("Error copying file:", err);
|
||||
});
|
||||
}
|
||||
}
|
135
Securite/Linkwarden/lib/api/storage/readFile.ts
Normal file
135
Securite/Linkwarden/lib/api/storage/readFile.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import {
|
||||
GetObjectCommand,
|
||||
GetObjectCommandInput,
|
||||
S3,
|
||||
} from "@aws-sdk/client-s3";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
import util from "util";
|
||||
|
||||
type ReturnContentTypes =
|
||||
| "text/plain"
|
||||
| "image/jpeg"
|
||||
| "image/png"
|
||||
| "application/pdf"
|
||||
| "application/json";
|
||||
|
||||
export default async function readFile(filePath: string) {
|
||||
let contentType: ReturnContentTypes;
|
||||
|
||||
if (s3Client) {
|
||||
const bucketParams: GetObjectCommandInput = {
|
||||
Bucket: process.env.SPACES_BUCKET_NAME,
|
||||
Key: filePath,
|
||||
};
|
||||
|
||||
try {
|
||||
let returnObject:
|
||||
| {
|
||||
file: Buffer | string;
|
||||
contentType: ReturnContentTypes;
|
||||
status: number;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
const headObjectAsync = util.promisify(
|
||||
s3Client.headObject.bind(s3Client)
|
||||
);
|
||||
|
||||
try {
|
||||
await headObjectAsync(bucketParams);
|
||||
} catch (err) {
|
||||
contentType = "text/plain";
|
||||
|
||||
returnObject = {
|
||||
file: "File not found.",
|
||||
contentType,
|
||||
status: 400,
|
||||
};
|
||||
}
|
||||
|
||||
if (!returnObject) {
|
||||
const response = await (s3Client as S3).send(
|
||||
new GetObjectCommand(bucketParams)
|
||||
);
|
||||
const data = await streamToBuffer(response.Body);
|
||||
|
||||
if (filePath.endsWith(".pdf")) {
|
||||
contentType = "application/pdf";
|
||||
} else if (filePath.endsWith(".png")) {
|
||||
contentType = "image/png";
|
||||
} else if (filePath.endsWith("_readability.json")) {
|
||||
contentType = "application/json";
|
||||
} else {
|
||||
// if (filePath.endsWith(".jpg"))
|
||||
contentType = "image/jpeg";
|
||||
}
|
||||
returnObject = { file: data as Buffer, contentType, status: 200 };
|
||||
}
|
||||
|
||||
return returnObject;
|
||||
} catch (err) {
|
||||
console.log("Error:", err);
|
||||
|
||||
contentType = "text/plain";
|
||||
return {
|
||||
file: "An internal occurred, please contact the support team.",
|
||||
contentType,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
|
||||
|
||||
if (filePath.endsWith(".pdf")) {
|
||||
contentType = "application/pdf";
|
||||
} else if (filePath.endsWith(".png")) {
|
||||
contentType = "image/png";
|
||||
} else if (filePath.endsWith("_readability.json")) {
|
||||
contentType = "application/json";
|
||||
} else {
|
||||
// if (filePath.endsWith(".jpg"))
|
||||
contentType = "image/jpeg";
|
||||
}
|
||||
|
||||
if (!fs.existsSync(creationPath))
|
||||
return {
|
||||
file: "File not found.",
|
||||
contentType: "text/plain",
|
||||
status: 404,
|
||||
};
|
||||
else {
|
||||
const file = fs.readFileSync(creationPath);
|
||||
return { file, contentType, status: 200 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the file's body into buffer
|
||||
const streamToBuffer = (stream: any) => {
|
||||
const chunks: any = [];
|
||||
return new Promise((resolve, reject) => {
|
||||
stream.on("data", (chunk: any) => chunks.push(Buffer.from(chunk)));
|
||||
stream.on("error", (err: any) => reject(err));
|
||||
stream.on("end", () => resolve(Buffer.concat(chunks)));
|
||||
});
|
||||
};
|
||||
|
||||
const fileNotFoundTemplate = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File not found</title>
|
||||
</head>
|
||||
<body style="margin-left: auto; margin-right: auto; max-width: 500px; padding: 1rem; font-family: sans-serif; background-color: rgb(251, 251, 251);">
|
||||
<h1>File not found</h1>
|
||||
<h2>It is possible that the file you're looking for either doesn't exist or hasn't been created yet.</h2>
|
||||
<h3>Some possible reasons are:</h3>
|
||||
<ul>
|
||||
<li>You are trying to access a file too early, before it has been fully archived. If that's the case, refreshing the page might resolve the issue.</li>
|
||||
<li>The file doesn't exist either because it encountered an error while being archived, or it simply doesn't exist.</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>`;
|
26
Securite/Linkwarden/lib/api/storage/removeFile.ts
Normal file
26
Securite/Linkwarden/lib/api/storage/removeFile.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
import { PutObjectCommandInput, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
||||
|
||||
export default async function removeFile({ filePath }: { filePath: string }) {
|
||||
if (s3Client) {
|
||||
const bucketParams: PutObjectCommandInput = {
|
||||
Bucket: process.env.SPACES_BUCKET_NAME,
|
||||
Key: filePath,
|
||||
};
|
||||
|
||||
try {
|
||||
await s3Client.send(new DeleteObjectCommand(bucketParams));
|
||||
} catch (err) {
|
||||
console.log("Error", err);
|
||||
}
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
|
||||
|
||||
fs.unlink(creationPath, (err) => {
|
||||
if (err) console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
62
Securite/Linkwarden/lib/api/storage/removeFolder.ts
Normal file
62
Securite/Linkwarden/lib/api/storage/removeFolder.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import s3Client from "./s3Client";
|
||||
import {
|
||||
DeleteObjectsCommand,
|
||||
DeleteObjectsCommandInput,
|
||||
ListObjectsCommand,
|
||||
} from "@aws-sdk/client-s3";
|
||||
|
||||
async function emptyS3Directory(bucket: string, dir: string) {
|
||||
if (s3Client) {
|
||||
const listParams = {
|
||||
Bucket: bucket,
|
||||
Prefix: dir,
|
||||
};
|
||||
|
||||
const deleteParams: DeleteObjectsCommandInput = {
|
||||
Bucket: bucket,
|
||||
Delete: { Objects: [] },
|
||||
};
|
||||
|
||||
const listedObjects = await s3Client.send(
|
||||
new ListObjectsCommand(listParams)
|
||||
);
|
||||
|
||||
if (listedObjects.Contents?.length === 0) return;
|
||||
|
||||
listedObjects.Contents?.forEach(({ Key }) => {
|
||||
deleteParams.Delete?.Objects?.push({ Key });
|
||||
});
|
||||
|
||||
console.log(listedObjects);
|
||||
|
||||
await s3Client.send(new DeleteObjectsCommand(deleteParams));
|
||||
|
||||
if (listedObjects.IsTruncated) await emptyS3Directory(bucket, dir);
|
||||
}
|
||||
}
|
||||
|
||||
export default async function removeFolder({ filePath }: { filePath: string }) {
|
||||
if (s3Client) {
|
||||
try {
|
||||
await emptyS3Directory(
|
||||
process.env.SPACES_BUCKET_NAME as string,
|
||||
filePath
|
||||
);
|
||||
} catch (err) {
|
||||
console.log("Error", err);
|
||||
}
|
||||
} else {
|
||||
const storagePath = process.env.STORAGE_FOLDER || "data";
|
||||
const creationPath = path.join(process.cwd(), storagePath + "/" + filePath);
|
||||
|
||||
try {
|
||||
fs.rmdirSync(creationPath, { recursive: true });
|
||||
} catch (error) {
|
||||
console.log(
|
||||
"Collection's archive directory wasn't deleted most likely because it didn't exist..."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
19
Securite/Linkwarden/lib/api/storage/s3Client.ts
Normal file
19
Securite/Linkwarden/lib/api/storage/s3Client.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { S3 } from "@aws-sdk/client-s3";
|
||||
|
||||
const s3Client: S3 | undefined =
|
||||
process.env.SPACES_ENDPOINT &&
|
||||
process.env.SPACES_REGION &&
|
||||
process.env.SPACES_KEY &&
|
||||
process.env.SPACES_SECRET
|
||||
? new S3({
|
||||
forcePathStyle: !!process.env.SPACES_FORCE_PATH_STYLE,
|
||||
endpoint: process.env.SPACES_ENDPOINT,
|
||||
region: process.env.SPACES_REGION,
|
||||
credentials: {
|
||||
accessKeyId: process.env.SPACES_KEY,
|
||||
secretAccessKey: process.env.SPACES_SECRET,
|
||||
},
|
||||
})
|
||||
: undefined;
|
||||
|
||||
export default s3Client;
|
Reference in New Issue
Block a user