mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
70 lines
2.7 KiB
C#
70 lines
2.7 KiB
C#
using System.Buffers.Binary;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
|
|
namespace Api.SeaHavenIndustries.Helper
|
|
{
|
|
public enum DocumentScanResult
|
|
{
|
|
Passed,
|
|
Infected,
|
|
Unavailable
|
|
}
|
|
|
|
public interface IDocumentScanner
|
|
{
|
|
Task<DocumentScanResult> ScanAsync(string path, CancellationToken cancellationToken);
|
|
}
|
|
|
|
public class ClamAvDocumentScanner : IDocumentScanner
|
|
{
|
|
private readonly IConfiguration _configuration;
|
|
|
|
public ClamAvDocumentScanner(IConfiguration configuration)
|
|
{
|
|
_configuration = configuration;
|
|
}
|
|
|
|
public async Task<DocumentScanResult> ScanAsync(string path, CancellationToken cancellationToken)
|
|
{
|
|
var host = _configuration["ClamAV:Host"];
|
|
var port = _configuration.GetValue<int?>("ClamAV:Port") ?? 3310;
|
|
if (string.IsNullOrWhiteSpace(host) || !File.Exists(path))
|
|
return DocumentScanResult.Unavailable;
|
|
|
|
try
|
|
{
|
|
using var client = new TcpClient();
|
|
await client.ConnectAsync(host, port, cancellationToken);
|
|
await using var network = client.GetStream();
|
|
await network.WriteAsync(Encoding.ASCII.GetBytes("zINSTREAM\0"), cancellationToken);
|
|
await using var file = File.OpenRead(path);
|
|
var buffer = new byte[64 * 1024];
|
|
while (true)
|
|
{
|
|
var count = await file.ReadAsync(buffer, cancellationToken);
|
|
if (count == 0) break;
|
|
var length = new byte[4];
|
|
BinaryPrimitives.WriteInt32BigEndian(length, count);
|
|
await network.WriteAsync(length, cancellationToken);
|
|
await network.WriteAsync(buffer.AsMemory(0, count), cancellationToken);
|
|
}
|
|
await network.WriteAsync(new byte[4], cancellationToken);
|
|
await network.FlushAsync(cancellationToken);
|
|
|
|
var responseBuffer = new byte[1024];
|
|
var responseLength = await network.ReadAsync(responseBuffer, cancellationToken);
|
|
var response = Encoding.ASCII.GetString(responseBuffer, 0, responseLength);
|
|
if (response.Contains("FOUND", StringComparison.OrdinalIgnoreCase))
|
|
return DocumentScanResult.Infected;
|
|
return response.Contains("OK", StringComparison.OrdinalIgnoreCase)
|
|
? DocumentScanResult.Passed
|
|
: DocumentScanResult.Unavailable;
|
|
}
|
|
catch (Exception) when (!cancellationToken.IsCancellationRequested)
|
|
{
|
|
return DocumentScanResult.Unavailable;
|
|
}
|
|
}
|
|
}
|
|
}
|