feat: enhance admin security, add img delete, optimize docker

This commit is contained in:
AI Assistant
2026-01-16 18:00:48 +07:00
parent 5bd3eb9b87
commit 6d0aef4163
5 changed files with 32 additions and 7 deletions

View File

@@ -7,7 +7,8 @@ WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json package-lock.json* ./
RUN npm install --ignore-scripts
COPY prisma ./prisma
RUN npm install
# Rebuild the source code only when needed
FROM base AS builder

5
package-lock.json generated
View File

@@ -29,6 +29,7 @@
"react": "19.2.3",
"react-dom": "19.2.3",
"react-hook-form": "^7.71.1",
"sharp": "^0.34.5",
"tailwind-merge": "^3.4.0",
"webpack": "^5.104.1",
"zod": "^4.3.5",
@@ -2480,7 +2481,6 @@
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
"integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
"license": "MIT",
"optional": true,
"engines": {
"node": ">=18"
}
@@ -6714,7 +6714,6 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
@@ -10859,7 +10858,6 @@
"integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
"hasInstallScript": true,
"license": "Apache-2.0",
"optional": true,
"dependencies": {
"@img/colour": "^1.0.0",
"detect-libc": "^2.1.2",
@@ -10903,7 +10901,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
"license": "ISC",
"optional": true,
"bin": {
"semver": "bin/semver.js"
},

View File

@@ -33,6 +33,7 @@
"react": "19.2.3",
"react-dom": "19.2.3",
"react-hook-form": "^7.71.1",
"sharp": "^0.34.5",
"tailwind-merge": "^3.4.0",
"webpack": "^5.104.1",
"zod": "^4.3.5",
@@ -56,4 +57,4 @@
"typescript": "^5",
"vitest": "^4.0.17"
}
}
}

View File

@@ -324,6 +324,16 @@ export async function loginUser(username: string, pass: string) {
}
}
// Security Check: If logging in as 'admin' with default password, BLOCK it if other users exist
if (username === 'admin' && pass === 'admin') {
const otherUsersCount = await prisma.user.count({
where: { username: { not: 'admin' } }
});
if (otherUsersCount > 0) {
return { success: false, error: "Tài khoản admin mặc định đã bị vô hiệu hóa vì hệ thống đã có người dùng mới." };
}
}
const user = await prisma.user.findUnique({ where: { username } });
if (!user) return { success: false, error: "Người dùng không tồn tại" };

View File

@@ -275,7 +275,23 @@ function EditMode({ item, locations, onCancel, onClose }: { item: any, locations
</div>
<div className="flex-1">
<Label>nh thiết bị</Label>
<Input type="file" accept="image/*" onChange={handleImageChange} className="mt-1 h-9 text-xs file:hidden" />
<div className="flex gap-2">
<Input type="file" accept="image/*" onChange={handleImageChange} className="mt-1 h-9 text-xs file:hidden" />
{imgPreview && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => {
setImgPreview(null);
form.setValue("image", "", { shouldDirty: true });
}}
className="mt-1 h-9 text-red-500 hover:bg-red-50 hover:text-red-600"
>
<Trash2 className="h-4 w-4 mr-1" /> Xóa nh
</Button>
)}
</div>
</div>
</div>