10 Descriptive message about your chansssges100

This commit is contained in:
yznahmad 2025-08-11 23:56:36 +03:00
parent 20505fc6e2
commit b4845dd435
5 changed files with 67 additions and 31 deletions

View File

@ -58,11 +58,14 @@ export async function PUT(req:Request)
// Validate logo if provided
if (logo && typeof logo === 'string') {
// Check if it's a valid SVG
if (!logo.includes('<svg') || !logo.includes('</svg>')) {
const isSvg = logo.includes('<svg') && logo.includes('</svg>');
const isPng = logo.startsWith('data:image/png;base64,');
// Check if it's a valid SVG or PNG data URL
if (!isSvg && !isPng) {
return NextResponse.json({
success: false,
message: "invalidSVGFile",
message: "invalidLogoFile",
}, {
status: 400,
headers: {
@ -71,10 +74,12 @@ export async function PUT(req:Request)
})
}
// Remove any script tags for security
const cleanLogo = logo.replace(/<script[^>]*>.*?<\/script>/gi, '');
// Update the logo variable with cleaned content
logo = cleanLogo;
// For SVG files, remove any script tags for security
if (isSvg) {
const cleanLogo = logo.replace(/<script[^>]*>.*?<\/script>/gi, '');
logo = cleanLogo;
}
// PNG data URLs are already safe as they're base64 encoded
}
// update the doc
let updated_doc = await userModel.updateMany({} , {

View File

@ -35,8 +35,8 @@ export default function GeneralSettings()
{ value: true, label: t('show') },
{ value: false, label: t('dontShow') },
]
// extract svg from svg file
const readFile = (file : Blob) => {
// extract content from svg or png file
const readFile = (file : Blob, fileType: string) => {
// this function return a promise
return new Promise((resolve, reject) => {
// read the file
@ -50,37 +50,48 @@ export default function GeneralSettings()
reader.onerror = (error) => {
reject(error);
};
// read the file as a text thene fire onload listener
reader.readAsText(file);
// read the file based on type
if (fileType === 'svg') {
reader.readAsText(file);
} else {
reader.readAsDataURL(file);
}
});
};
// handle the changes in the file input
const handleFileChange = async (event : any , setFieldValue : any) => {
const file = event.target.files[0];
if (file) {
// Validate file type
if (!file.type.includes('svg') && !file.name.toLowerCase().endsWith('.svg')) {
alert(t('onlySVGFilesAllowed') || 'Only SVG files are allowed');
// Validate file type - allow both SVG and PNG
const isSvg = file.type.includes('svg') || file.name.toLowerCase().endsWith('.svg');
const isPng = file.type.includes('png') || file.name.toLowerCase().endsWith('.png');
if (!isSvg && !isPng) {
alert(t('onlySVGAndPNGFilesAllowed') || 'Only SVG and PNG files are allowed');
event.target.value = ''; // Clear the input
return;
}
try {
const fileType = isSvg ? 'svg' : 'png';
// get the file content
const content = await readFile(file) as string;
const content = await readFile(file, fileType) as string;
// Validate SVG content
if (!content.includes('<svg') || !content.includes('</svg>')) {
alert(t('invalidSVGFile') || 'Invalid SVG file format');
event.target.value = ''; // Clear the input
return;
if (fileType === 'svg') {
// Validate SVG content
if (!content.includes('<svg') || !content.includes('</svg>')) {
alert(t('invalidSVGFile') || 'Invalid SVG file format');
event.target.value = ''; // Clear the input
return;
}
// Additional security check - remove any script tags
const cleanContent = content.replace(/<script[^>]*>.*?<\/script>/gi, '');
setFieldValue('logo' , cleanContent);
} else {
// For PNG files, store the data URL directly
setFieldValue('logo' , content);
}
// Additional security check - remove any script tags
const cleanContent = content.replace(/<script[^>]*>.*?<\/script>/gi, '');
// set the field value with with new file content
setFieldValue('logo' , cleanContent)
} catch (error) {
console.error('Error reading file:', error);
alert(t('errorReadingFile') || 'Error reading file');
@ -343,13 +354,21 @@ export default function GeneralSettings()
dark:border-primary-dark rounded-md
overflow-hidden flex items-center justify-center
`}>
<div className="overflow-hidden [&_svg]:max-w-[100px] [&_svg]:max-h-[100px]" dangerouslySetInnerHTML={{ __html: values.logo }} />
{values.logo && values.logo.startsWith('data:image/png') ? (
<img
src={values.logo}
alt="Logo"
className="max-w-[100px] max-h-[100px] object-contain"
/>
) : (
<div className="overflow-hidden [&_svg]:max-w-[100px] [&_svg]:max-h-[100px]" dangerouslySetInnerHTML={{ __html: values.logo }} />
)}
</label>
<input
onChange={((e) => {
handleFileChange(e , setFieldValue)
})}
accept=".svg"
accept=".svg,.png"
disabled={!edite}
className="invisible w-0 h-0 hidden"
type="file"

View File

@ -46,7 +46,17 @@ export default function Sidebar () {
<nav className={`fixed top-0 ltr:left-0 rtl:right-0 lg:relative shadow-[5px_0_25px_0_rgba(94,92,154,0.1)] z-[99] h-screen bg-primary-dark dark:bg-primary-dark duration-300 ${sidebarState ? 'min-w-[260px] max-w-[260px] ' : 'ltr:translate-x-[-260px] rtl:translate-x-[260px] w-0'}`}>
<header className="w-full max-h-[64px] flex justify-between items-center px-[18px] py-[14px] [&_*]:text-text-light bg-secondary-dark">
<div className="flex justify-center items-center flex gap-[15px]">
<div className={`w-12 h-16 flex items-center justify-center relative ${appGeneralSettings.showLogo ? '' : 'hidden'}`} dangerouslySetInnerHTML={{ __html: appGeneralSettings.logo || '' }} />
<div className={`w-12 h-16 flex items-center justify-center relative ${appGeneralSettings.showLogo ? '' : 'hidden'}`}>
{appGeneralSettings.logo && appGeneralSettings.logo.startsWith('data:image/png') ? (
<img
src={appGeneralSettings.logo}
alt="Logo"
className="max-w-full max-h-full object-contain"
/>
) : (
<div dangerouslySetInnerHTML={{ __html: appGeneralSettings.logo || '' }} />
)}
</div>
<h1 className="text-[25px] font-light">{local == 'ar' ? appGeneralSettings.appName : appGeneralSettings.appNameEN}</h1>
</div>
<button onClick={() => {dispatch(toggleSidebar())}} className="rounded-full rtl:rotate-180 hover:bg-primary/5 p-[6px]">

View File

@ -365,8 +365,9 @@
"save": "الحفظ",
"ignore": "تجاهل",
"appNameEN": "اسم التطبيق ( en )",
"onlySVGFilesAllowed": "يُسمح فقط بملفات SVG",
"onlySVGAndPNGFilesAllowed": "يُسمح فقط بملفات SVG و PNG",
"invalidSVGFile": "تنسيق ملف SVG غير صالح",
"invalidLogoFile": "تنسيق ملف الشعار غير صالح. يُسمح فقط بملفات SVG و PNG",
"errorReadingFile": "خطأ في قراءة الملف"
},
"statistics": {

View File

@ -369,8 +369,9 @@
"edite": "Edite",
"save": "Save",
"ignore": "Ignore",
"onlySVGFilesAllowed": "Only SVG files are allowed",
"onlySVGAndPNGFilesAllowed": "Only SVG and PNG files are allowed",
"invalidSVGFile": "Invalid SVG file format",
"invalidLogoFile": "Invalid logo file format. Only SVG and PNG files are allowed",
"errorReadingFile": "Error reading file"
},
"statistics": {