mktcms 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +8 -5
- package/dist/runtime/app/components/content/index.vue +5 -17
- package/dist/runtime/app/components/content/upload.vue +7 -3
- package/dist/runtime/app/composables/useFileType.js +6 -6
- package/dist/runtime/app/pages/admin/login.vue +34 -7
- package/dist/runtime/server/api/admin/blob.js +4 -3
- package/dist/runtime/server/api/admin/csv.js +3 -2
- package/dist/runtime/server/api/admin/csv.post.js +6 -4
- package/dist/runtime/server/api/admin/delete.js +6 -4
- package/dist/runtime/server/api/admin/download.js +11 -8
- package/dist/runtime/server/api/admin/git-branch.js +3 -2
- package/dist/runtime/server/api/admin/git-history.js +3 -2
- package/dist/runtime/server/api/admin/git-update-status.js +3 -2
- package/dist/runtime/server/api/admin/git-update.post.js +2 -2
- package/dist/runtime/server/api/admin/image.post.js +14 -10
- package/dist/runtime/server/api/admin/list.js +11 -6
- package/dist/runtime/server/api/admin/login.js +6 -4
- package/dist/runtime/server/api/admin/logout.js +2 -1
- package/dist/runtime/server/api/admin/md.js +3 -2
- package/dist/runtime/server/api/admin/md.post.js +6 -4
- package/dist/runtime/server/api/admin/pdf.post.js +13 -9
- package/dist/runtime/server/api/admin/txt.js +3 -2
- package/dist/runtime/server/api/admin/txt.post.js +6 -4
- package/dist/runtime/server/api/admin/upload.js +10 -6
- package/dist/runtime/server/api/content/[path].js +14 -12
- package/dist/runtime/server/api/content/list.js +9 -7
- package/dist/runtime/server/middleware/auth.js +2 -1
- package/dist/runtime/server/utils/authCookie.d.ts +9 -0
- package/dist/runtime/server/utils/authCookie.js +12 -0
- package/dist/runtime/server/utils/contentKey.d.ts +2 -0
- package/dist/runtime/server/utils/contentKey.js +67 -0
- package/dist/runtime/server/utils/gitErrorSanitization.d.ts +1 -0
- package/dist/runtime/server/utils/gitErrorSanitization.js +17 -0
- package/dist/runtime/server/utils/gitVersioning.d.ts +1 -2
- package/dist/runtime/server/utils/gitVersioning.js +2 -13
- package/dist/runtime/server/utils/loginRateLimit.d.ts +4 -0
- package/dist/runtime/server/utils/loginRateLimit.js +72 -0
- package/dist/runtime/server/utils/uploadGuard.d.ts +2 -0
- package/dist/runtime/server/utils/uploadGuard.js +20 -0
- package/dist/runtime/shared/contentFiles.d.ts +15 -0
- package/dist/runtime/shared/contentFiles.js +38 -0
- package/package.json +1 -1
- package/dist/runtime/app/composables/useImport.d.ts +0 -6
- package/dist/runtime/app/composables/useImport.js +0 -37
- package/dist/runtime/server/api/admin/import.d.ts +0 -5
- package/dist/runtime/server/api/admin/import.js +0 -86
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { createError, defineEventHandler, readMultipartFormData } from "h3";
|
|
2
|
-
import { useStorage } from "nitropack/runtime";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import unzipper from "unzipper";
|
|
5
|
-
function sanitizePathSegment(segment) {
|
|
6
|
-
return segment.replace(/[/:\\]/g, "_").replace(/\0/g, "");
|
|
7
|
-
}
|
|
8
|
-
function zipPathToColonKey(entryPath) {
|
|
9
|
-
const original = entryPath.replace(/\\/g, "/");
|
|
10
|
-
if (original.startsWith("/")) {
|
|
11
|
-
return "";
|
|
12
|
-
}
|
|
13
|
-
let p = original.replace(/^\.\//, "");
|
|
14
|
-
if (/^[a-z]:\//i.test(p)) {
|
|
15
|
-
return "";
|
|
16
|
-
}
|
|
17
|
-
if (!p || p.includes("\0")) {
|
|
18
|
-
return "";
|
|
19
|
-
}
|
|
20
|
-
p = path.posix.normalize(p);
|
|
21
|
-
if (p === "." || p === ".." || p.startsWith("../") || p.includes("/../")) {
|
|
22
|
-
return "";
|
|
23
|
-
}
|
|
24
|
-
const parts = p.split("/").filter(Boolean);
|
|
25
|
-
if (parts.some((part) => part === "." || part === "..")) {
|
|
26
|
-
return "";
|
|
27
|
-
}
|
|
28
|
-
const sanitizedParts = parts.map(sanitizePathSegment);
|
|
29
|
-
return sanitizedParts.join(":");
|
|
30
|
-
}
|
|
31
|
-
export default defineEventHandler(async (event) => {
|
|
32
|
-
const form = await readMultipartFormData(event);
|
|
33
|
-
if (!form) {
|
|
34
|
-
throw createError({
|
|
35
|
-
statusCode: 400,
|
|
36
|
-
statusMessage: "No form data received"
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
const file = form.find((item) => item.name === "file");
|
|
40
|
-
if (!file) {
|
|
41
|
-
throw createError({
|
|
42
|
-
statusCode: 400,
|
|
43
|
-
statusMessage: "Missing file"
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (!file.filename || !file.data) {
|
|
47
|
-
throw createError({
|
|
48
|
-
statusCode: 400,
|
|
49
|
-
statusMessage: "Invalid file upload"
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
const allowedExtensions = [".zip"];
|
|
53
|
-
const fileExtension = file.filename.toLowerCase().slice(file.filename.lastIndexOf("."));
|
|
54
|
-
if (!allowedExtensions.includes(fileExtension)) {
|
|
55
|
-
throw createError({
|
|
56
|
-
statusCode: 400,
|
|
57
|
-
statusMessage: "Invalid file type. Only ZIP files are allowed for import."
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
const zipBuffer = Buffer.isBuffer(file.data) ? file.data : Buffer.from(file.data);
|
|
61
|
-
let zip;
|
|
62
|
-
try {
|
|
63
|
-
zip = await unzipper.Open.buffer(zipBuffer);
|
|
64
|
-
} catch {
|
|
65
|
-
throw createError({ statusCode: 400, statusMessage: "Invalid ZIP file" });
|
|
66
|
-
}
|
|
67
|
-
const storage = useStorage("content");
|
|
68
|
-
const written = /* @__PURE__ */ new Set();
|
|
69
|
-
for (const entry of zip.files) {
|
|
70
|
-
if (!entry.path) {
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (entry.type === "Directory") continue;
|
|
74
|
-
const fileColonKey = zipPathToColonKey(entry.path);
|
|
75
|
-
if (!fileColonKey) {
|
|
76
|
-
throw createError({
|
|
77
|
-
statusCode: 400,
|
|
78
|
-
statusMessage: `Invalid ZIP entry path: ${entry.path}`
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
const data = await entry.buffer();
|
|
82
|
-
await storage.setItemRaw(fileColonKey, data);
|
|
83
|
-
written.add(fileColonKey);
|
|
84
|
-
}
|
|
85
|
-
return { success: true, count: written.size };
|
|
86
|
-
});
|