cdn
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using Vizhtalk.CDN.Presentation.TypeIds;
|
||||
using Vizhtalk.CDN.Presentation.ValueObjects;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.Entities
|
||||
{
|
||||
public class Media : Entity<MediaId>
|
||||
{
|
||||
public MediaName Name { get; set; }
|
||||
public ContentType ContentType { get; private set; }
|
||||
public string Path { get; private set; }
|
||||
public string Hash { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapGet("/", () => "Hello World!");
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:11814",
|
||||
"sslPort": 44357
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5041",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7109;http://localhost:5041",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.TypeIds
|
||||
{
|
||||
public class MediaId : TypedIdValueBase<Guid>
|
||||
{
|
||||
public MediaId(Guid value) : base(value)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Vizhtalk.CDN.Presentation.ValueObjects.Rules;
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.ValueObjects
|
||||
{
|
||||
public class ContentType : ValueObject
|
||||
{
|
||||
public ContentType(string contentType, byte[] fileBytes)
|
||||
{
|
||||
CheckRule(new ValidContentTypeRule(contentType, fileBytes));
|
||||
|
||||
Value = contentType;
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
using VizhTalk.BuildingBlocks.Domain.Guards;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.ValueObjects
|
||||
{
|
||||
public class MediaName : ValueObject
|
||||
{
|
||||
public MediaName(string value)
|
||||
{
|
||||
Guard.NullOrEmpty(value, nameof(MediaName));
|
||||
Guard.MaxLength(value, nameof(MediaName), 150);
|
||||
|
||||
Value = value;
|
||||
}
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
using VizhTalk.BuildingBlocks.Domain.Exceptions;
|
||||
|
||||
namespace Vizhtalk.CDN.Presentation.ValueObjects.Rules;
|
||||
|
||||
public class ValidContentTypeRule(string contentType, byte[] fileBytes) : IBusinessRule
|
||||
{
|
||||
|
||||
public string Message => $"{contentType} content type is not supported or file content is invalid";
|
||||
|
||||
public bool IsBroken()
|
||||
{
|
||||
// اول MimeType بررسی میشه
|
||||
if (!_validContentTypes.Contains(contentType))
|
||||
return true;
|
||||
|
||||
// بعد Magic Number بررسی میشه
|
||||
if (!HasValidMagicNumber(contentType, fileBytes))
|
||||
return true;
|
||||
|
||||
// اگر SVG باشه → محتوای XML رو بررسی کنیم
|
||||
if (contentType.Equals("image/svg+xml", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (ContainsDangerousSvgContent(fileBytes))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // یعنی مشکلی نیست
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> _validContentTypes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// Images
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/webp",
|
||||
"image/bmp",
|
||||
"image/tiff",
|
||||
"image/svg+xml",
|
||||
|
||||
// Videos
|
||||
"video/mp4",
|
||||
"video/webm",
|
||||
"video/ogg",
|
||||
"video/mpeg",
|
||||
"video/3gpp",
|
||||
"video/3gpp2",
|
||||
"video/x-msvideo",
|
||||
"video/x-matroska",
|
||||
|
||||
// Audios
|
||||
"audio/mpeg",
|
||||
"audio/wav",
|
||||
"audio/ogg",
|
||||
"audio/webm",
|
||||
"audio/aac",
|
||||
"audio/flac",
|
||||
"audio/mp4",
|
||||
"audio/3gpp",
|
||||
"audio/3gpp2"
|
||||
};
|
||||
|
||||
private static bool HasValidMagicNumber(string contentType, byte[] fileBytes)
|
||||
{
|
||||
if (fileBytes == null || fileBytes.Length < 4)
|
||||
return false;
|
||||
|
||||
// فقط چند مورد رایج رو گذاشتم (میشه کاملترش کرد)
|
||||
if (contentType == "image/png" && fileBytes.Take(8).SequenceEqual(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }))
|
||||
return true;
|
||||
|
||||
if (contentType == "image/jpeg" && fileBytes.Take(2).SequenceEqual(new byte[] { 0xFF, 0xD8 }))
|
||||
return true;
|
||||
|
||||
if (contentType == "image/gif" && Encoding.ASCII.GetString(fileBytes.Take(3).ToArray()) == "GIF")
|
||||
return true;
|
||||
|
||||
if (contentType == "video/mp4" && Encoding.ASCII.GetString(fileBytes.Skip(4).Take(4).ToArray()).Contains("ftyp"))
|
||||
return true;
|
||||
|
||||
if (contentType == "audio/mpeg" && (fileBytes.Take(3).SequenceEqual(new byte[] { 0x49, 0x44, 0x33 }) // ID3
|
||||
|| (fileBytes[0] == 0xFF && (fileBytes[1] & 0xE0) == 0xE0))) // MPEG frame
|
||||
return true;
|
||||
|
||||
if (contentType == "image/svg+xml")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ContainsDangerousSvgContent(byte[] fileBytes)
|
||||
{
|
||||
string content = Encoding.UTF8.GetString(fileBytes);
|
||||
|
||||
// اگر اسکریپت یا onload یا event handler باشه → خطرناک
|
||||
string pattern = @"<script|onload=|onerror=|javascript:";
|
||||
return Regex.IsMatch(content, pattern, RegexOptions.IgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Infrastructure\VizhTalk.BuildingBlocks.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Infrastructure\" />
|
||||
<Folder Include="Application\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"VizhTalk.CDN": "mongodb://localhost:27017/VizhTalk.CDN"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
Reference in New Issue
Block a user