cdn
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public class EncryptionIdHelper
|
||||
{
|
||||
private const string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
public static string Encrypt(string input)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
||||
|
||||
// تبدیل بایتها به عدد بزرگ
|
||||
var number = new System.Numerics.BigInteger(bytes);
|
||||
|
||||
// اگر منفی شد، مثبتش کن
|
||||
if (number < 0) number = -number;
|
||||
|
||||
// تبدیل به Base62
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (number > 0)
|
||||
{
|
||||
result.Insert(0, Alphabet[(int)(number % 62)]);
|
||||
number /= 62;
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public static string Decrypt(string encoded)
|
||||
{
|
||||
System.Numerics.BigInteger number = 0;
|
||||
foreach (char c in encoded)
|
||||
{
|
||||
number = number * 62 + Alphabet.IndexOf(c);
|
||||
}
|
||||
|
||||
// تبدیل دوباره به بایت
|
||||
byte[] bytes = number.ToByteArray();
|
||||
|
||||
// رشته اصلی
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
@@ -17,4 +17,6 @@ public class BusinessRuleValidationException : Exception
|
||||
{
|
||||
return $"{BrokenRule.GetType().FullName}: {BrokenRule.Message}";
|
||||
}
|
||||
public string GetFullName()
|
||||
=> BrokenRule.GetType()?.FullName!;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
public abstract class TypedIdValueBase<T> : IEquatable<TypedIdValueBase<T>> , ITypeIdValueBase
|
||||
public abstract class TypedIdValueBase<T> : IEquatable<TypedIdValueBase<T>>, ITypeIdValueBase
|
||||
{
|
||||
public T Value { get; }
|
||||
|
||||
@@ -32,7 +32,7 @@ public abstract class TypedIdValueBase<T> : IEquatable<TypedIdValueBase<T>> , IT
|
||||
|
||||
public bool Equals(TypedIdValueBase<T>? other)
|
||||
{
|
||||
if(other == null)
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return EqualityComparer<T>.Default.Equals(this.Value, other.Value);
|
||||
@@ -59,5 +59,7 @@ public abstract class TypedIdValueBase<T> : IEquatable<TypedIdValueBase<T>> , IT
|
||||
return !(x == y);
|
||||
}
|
||||
}
|
||||
public interface ITypeIdValueBase { }
|
||||
public interface ITypeIdValueBase
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace VizhTalk.CDN.Domain.Entities;
|
||||
|
||||
public class Media
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
namespace VizhTalk.CDN.Domain.Entities
|
||||
{
|
||||
internal class User
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Domain\VizhTalk.BuildingBlocks.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Infrastructure\VizhTalk.BuildingBlocks.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\Vizhtalk.CDN.Application\Vizhtalk.CDN.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -14,6 +14,7 @@ builder.Services.AddScoped<LanguageMutation>();
|
||||
builder.AddGraphQL()
|
||||
.AddQueryType<LanguageQuery>()
|
||||
.AddMutationType<LanguageMutation>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapGraphQL();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Mapster;
|
||||
using VizhTalk.Grpc.Learning;
|
||||
using VizhTalk.Grpc.Learning.Language;
|
||||
using VizhTalk.Learning.Domain.Entities;
|
||||
|
||||
@@ -10,8 +11,12 @@ namespace VizhTalk.Learning.Application.Mappers
|
||||
{
|
||||
|
||||
var config = TypeAdapterConfig<Language, LanguageDTO>.NewConfig()
|
||||
.Map(x => x.Title, des => des.Title.Value)
|
||||
.Map(x=>x.Id, des=> des.Id == null ? 0 : des.Id.Value);
|
||||
.MapWith(lan => new LanguageDTO()
|
||||
{
|
||||
Id = lan.Id.Value,
|
||||
Title = lan.Title.Value,
|
||||
});
|
||||
|
||||
|
||||
config.Compile();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ public class GetAllLanguageQueryHandler(IGenericDapper<LanguageDTO> languageDapp
|
||||
var result = new GetAllLanguageDTO();
|
||||
var sql = $"select * from Learning.Languages";
|
||||
var language = await languageDapper.GetAllAsync(sql);
|
||||
result.Language.AddRange(language);
|
||||
result.Languages.AddRange(language);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -20,10 +20,20 @@ public class GetLanguageByTitleQueryHandler(IGenericDapper<LanguageDTO> language
|
||||
{
|
||||
public async Task<LanguageDTO> Handle(GetLanguageByTitleQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var sql = $"select * from Learning.Languages where Title = " +
|
||||
$" @{nameof(Language.Title)}";
|
||||
var sql = $"select * from Learning.Languages where Title = @{nameof(Language.Title)}";
|
||||
|
||||
var language = await languageDapper.GetAsync(sql, new { request.Title });
|
||||
return language;
|
||||
}
|
||||
}
|
||||
public class GetLanguageByIdQueryHandler(IGenericDapper<LanguageDTO> languageDapper) : IQueryHandler<GetLanguageByIdQuery, LanguageDTO>
|
||||
{
|
||||
public async Task<LanguageDTO> Handle(GetLanguageByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var sql = $"select * from Learning.Languages where Id = " +
|
||||
$" @{nameof(Language.Id)}";
|
||||
|
||||
var language = await languageDapper.GetAsync(sql, new { request.Id });
|
||||
return language;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace VizhTalk.Learning.Domain.ValueObjects
|
||||
title = title.Trim();
|
||||
Guard.NullOrEmpty(title, nameof(LanguageTitle));
|
||||
Guard.MaxLength(title, nameof(LanguageTitle), 60);
|
||||
|
||||
Value = title;
|
||||
}
|
||||
public string Value { get; private set; }
|
||||
|
||||
@@ -23,4 +23,9 @@ public class LanguageService(ILearningModule learningModule) : LanguageGrpc.Lang
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
}
|
||||
public override async Task<LanguageDTO> GetById(GetLanguageByIdQuery request, ServerCallContext context)
|
||||
{
|
||||
return await learningModule.Execute(request, context.CancellationToken);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning.Helpers
|
||||
{
|
||||
internal class CompressionHelper
|
||||
{
|
||||
public static byte[] Compress(byte[] data)
|
||||
{
|
||||
using var output = new MemoryStream();
|
||||
using (var gzip = new GZipStream(output, CompressionMode.Compress))
|
||||
{
|
||||
gzip.Write(data, 0, data.Length);
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] compressedData)
|
||||
{
|
||||
using var input = new MemoryStream(compressedData);
|
||||
using var gzip = new GZipStream(input, CompressionMode.Decompress);
|
||||
using var output = new MemoryStream();
|
||||
gzip.CopyTo(output);
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning.Helpers
|
||||
{
|
||||
internal class EncryptionHelper
|
||||
{
|
||||
private const string Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
public static string Encrypt(string input)
|
||||
{
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
||||
|
||||
// تبدیل بایتها به عدد بزرگ
|
||||
var number = new System.Numerics.BigInteger(bytes);
|
||||
|
||||
// اگر منفی شد، مثبتش کن
|
||||
if (number < 0) number = -number;
|
||||
|
||||
// تبدیل به Base62
|
||||
StringBuilder result = new StringBuilder();
|
||||
while (number > 0)
|
||||
{
|
||||
result.Insert(0, Alphabet[(int)(number % 62)]);
|
||||
number /= 62;
|
||||
}
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public static string Decrypt(string encoded)
|
||||
{
|
||||
System.Numerics.BigInteger number = 0;
|
||||
foreach (char c in encoded)
|
||||
{
|
||||
number = number * 62 + Alphabet.IndexOf(c);
|
||||
}
|
||||
|
||||
// تبدیل دوباره به بایت
|
||||
byte[] bytes = number.ToByteArray();
|
||||
|
||||
// رشته اصلی
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using VizhTalk.BuildingBlocks.Domain;
|
||||
|
||||
namespace VizhTalk.Grpc.Learning;
|
||||
|
||||
public sealed partial class Id
|
||||
{
|
||||
public static implicit operator string(Id id)
|
||||
=> EncryptionIdHelper.Decrypt(id.Value);
|
||||
|
||||
public static implicit operator Id(string id)
|
||||
=> new Id()
|
||||
{
|
||||
Value = EncryptionIdHelper.Encrypt(id)
|
||||
};
|
||||
|
||||
public static implicit operator int(Id id)
|
||||
=> int.Parse(EncryptionIdHelper.Decrypt(id.Value));
|
||||
|
||||
public static implicit operator Guid(Id id)
|
||||
=> Guid.Parse(EncryptionIdHelper.Decrypt(id.Value));
|
||||
|
||||
public static implicit operator long(Id id)
|
||||
=> long.Parse(EncryptionIdHelper.Decrypt(id.Value));
|
||||
|
||||
|
||||
public static implicit operator Id(int id)
|
||||
=> (Id)id.ToString();
|
||||
|
||||
public static implicit operator Id(long id)
|
||||
=> (Id)id.ToString();
|
||||
|
||||
public static implicit operator Id(Guid id)
|
||||
=> (Id)id.ToString();
|
||||
}
|
||||
@@ -3,6 +3,7 @@ syntax="proto3";
|
||||
option csharp_namespace="VizhTalk.Grpc.Learning.Language";
|
||||
|
||||
package greet;
|
||||
import "Proto/Shared.proto";
|
||||
|
||||
|
||||
message CreateLanguageCommand{
|
||||
@@ -10,6 +11,6 @@ message CreateLanguageCommand{
|
||||
}
|
||||
|
||||
message UpdateLanguageCommand{
|
||||
int32 Id = 1;
|
||||
Id Id = 1;
|
||||
string title = 2;
|
||||
}
|
||||
@@ -3,13 +3,14 @@ syntax="proto3";
|
||||
option csharp_namespace="VizhTalk.Grpc.Learning.Language";
|
||||
|
||||
package greet;
|
||||
import "Proto/Shared.proto";
|
||||
|
||||
message LanguageDTO {
|
||||
string Id = 1;
|
||||
Id Id = 1;
|
||||
string title = 2;
|
||||
}
|
||||
|
||||
|
||||
message GetAllLanguageDTO{
|
||||
repeated LanguageDTO language =1;
|
||||
repeated LanguageDTO languages =1;
|
||||
}
|
||||
@@ -4,9 +4,14 @@ option csharp_namespace="VizhTalk.Grpc.Learning.Language";
|
||||
|
||||
package greet;
|
||||
|
||||
import "Proto/Shared.proto";
|
||||
|
||||
message GetAllLanguageQuery{
|
||||
}
|
||||
message GetLanguageByTitleQuery{
|
||||
string title = 1;
|
||||
}
|
||||
|
||||
message GetLanguageByIdQuery{
|
||||
Id id=1;
|
||||
}
|
||||
@@ -18,4 +18,5 @@ service LanguageGrpc {
|
||||
rpc Update (UpdateLanguageCommand) returns (LanguageDTO);
|
||||
rpc GetAll (GetAllLanguageQuery) returns (GetAllLanguageDTO);
|
||||
rpc GetByTitle (GetLanguageByTitleQuery) returns (LanguageDTO);
|
||||
rpc GetById (GetLanguageByIdQuery) returns (LanguageDTO);
|
||||
}
|
||||
@@ -7,3 +7,6 @@ package greet;
|
||||
message Empty{
|
||||
|
||||
}
|
||||
message Id{
|
||||
string value = 1;
|
||||
}
|
||||
@@ -5,3 +5,4 @@ namespace VizhTalk.Grpc.Learning.Language;
|
||||
|
||||
public sealed partial class GetAllLanguageQuery : IQuery<GetAllLanguageDTO>;
|
||||
public sealed partial class GetLanguageByTitleQuery : IQuery<LanguageDTO>;
|
||||
public sealed partial class GetLanguageByIdQuery : IQuery<LanguageDTO>;
|
||||
|
||||
@@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.Learning.Presentat
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VizhTalk.Gateway.Web.BFF", "VizhTalk.Gateway.BFF\VizhTalk.Gateway.Web.BFF.csproj", "{21DDD623-E75A-4D16-894B-2DEA0CA5C073}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vizhtalk.CDN.Presentation", "Vizhtalk.CDN.Presentation\Vizhtalk.CDN.Presentation.csproj", "{F6FDEF63-77D7-47AC-A5F5-2EB59D230158}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -89,6 +91,10 @@ Global
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F6FDEF63-77D7-47AC-A5F5-2EB59D230158}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F6FDEF63-77D7-47AC-A5F5-2EB59D230158}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F6FDEF63-77D7-47AC-A5F5-2EB59D230158}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F6FDEF63-77D7-47AC-A5F5-2EB59D230158}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -112,6 +118,7 @@ Global
|
||||
{A3F0C4E9-3957-4B25-8AB5-6751ECB01F39} = {16D91427-4F51-48CD-A2F2-6CC1B9A9D8A5}
|
||||
{8327C994-F1D5-493B-8EF7-B60EB888E92A} = {1305E6AB-69E5-47BD-B03C-694832C4D46A}
|
||||
{21DDD623-E75A-4D16-894B-2DEA0CA5C073} = {FCA7DC48-FD9C-43FA-AC1B-464049337778}
|
||||
{F6FDEF63-77D7-47AC-A5F5-2EB59D230158} = {9E64DF44-8256-40C8-8AFA-B841CE80DD0E}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {9BD8917D-0A5E-401B-B153-400D610B23E4}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\VizhTalk.BuildingBlocks.Application\VizhTalk.BuildingBlocks.Application.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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