fix access to path

This commit is contained in:
misya 2025-05-14 10:06:51 +08:00
parent 0b298c7965
commit 6ee24de227
4 changed files with 200 additions and 80 deletions

View File

@ -13,7 +13,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
{
private readonly MMSSystemContext _context;//Used in TarBallForm and GeneratePdfResponse to query the database.
private readonly NetworkShareAccess _networkAccessService;//used in GetImage and GeneratePdfResponse
private const string PhotoBasePath = "\\\\192.168.12.42\\images\\marine\\manual_tarball";//used in GetImage and GeneratePdfResponse
private const string PhotoBasePath = @"\\192.168.12.42\images\marine\manual_tarball";//used in GetImage and GeneratePdfResponse
public MarineController(MMSSystemContext context, NetworkShareAccess networkAccessService)
{
@ -77,32 +77,119 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
public IActionResult GetImage(string fileName)
{
if (string.IsNullOrEmpty(fileName))
{
return BadRequest("Filename cannot be empty");
}
// Sanitize filename to prevent path traversal attacks
var sanitizedFileName = Path.GetFileName(fileName);
if (sanitizedFileName != fileName)
{
return BadRequest("Invalid filename");
}
int retryCount = 0;
const int maxRetries = 3;
bool connectionSuccess = false;
// Retry loop for network connection
while (retryCount < maxRetries && !connectionSuccess)
{
try
{
Console.WriteLine($"Attempt {retryCount + 1} to connect to network share...");
// Connect to network share
_networkAccessService.ConnectToNetworkPath();
connectionSuccess = true;
Console.WriteLine("Network share connected successfully");
}
catch (Exception ex)
{
retryCount++;
Console.WriteLine($"Connection attempt {retryCount} failed: {ex.Message}");
if (retryCount >= maxRetries)
{
Console.WriteLine($"Max connection attempts reached. Last error: {ex}");
return StatusCode(503, $"Could not establish connection to image server after {maxRetries} attempts");
}
// Wait before retrying (1s, 2s, 3s)
Thread.Sleep(1000 * retryCount);
}
}
try
{
// Connect to the network path
_networkAccessService.ConnectToNetworkPath();
string imagePath = Path.Combine(PhotoBasePath, sanitizedFileName);
Console.WriteLine($"Attempting to access image at: {imagePath}");
string imagePath = Path.Combine(PhotoBasePath, fileName);
// Verify file exists
if (!System.IO.File.Exists(imagePath))
{
Console.WriteLine($"Image not found at path: {imagePath}");
return NotFound($"Image '{sanitizedFileName}' not found on server");
}
if (System.IO.File.Exists(imagePath))
// Verify file is an image
if (!IsImageValid(imagePath))
{
byte[] imageBytes = System.IO.File.ReadAllBytes(imagePath);
return File(imageBytes, "image/jpeg");
Console.WriteLine($"Invalid image file at path: {imagePath}");
return BadRequest("The requested file is not a valid image");
}
else
// Read and return the image
byte[] imageBytes = System.IO.File.ReadAllBytes(imagePath);
Console.WriteLine($"Successfully read image: {sanitizedFileName} ({imageBytes.Length} bytes)");
// Determine content type based on extension
string contentType = "image/jpeg"; // default
string extension = Path.GetExtension(sanitizedFileName)?.ToLower();
if (extension == ".png")
{
return NotFound("Image not found.");
contentType = "image/png";
}
else if (extension == ".gif")
{
contentType = "image/gif";
}
return File(imageBytes, contentType);
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"Access denied to image: {ex}");
return StatusCode(403, "Access to the image was denied");
}
catch (IOException ex)
{
Console.WriteLine($"IO error accessing image: {ex}");
return StatusCode(503, "Error accessing image file");
}
catch (Exception ex)
{
Console.WriteLine($"Error retrieving image: {ex.Message}");
return StatusCode(500, "Error retrieving image.");
Console.WriteLine($"Unexpected error: {ex}");
return StatusCode(500, "An unexpected error occurred while processing the image");
}
finally
{
// Disconnect from the network path
_networkAccessService.DisconnectFromNetworkShare();
try
{
if (connectionSuccess)
{
Console.WriteLine("Disconnecting from network share...");
_networkAccessService.DisconnectFromNetworkShare();
}
}
catch (Exception ex)
{
Console.WriteLine($"Warning: Error disconnecting from share: {ex.Message}");
// Don't fail the request because of disconnect issues
}
}
}
@ -113,13 +200,41 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
public IActionResult ViewPDF(int id)
{
return GeneratePdfResponse(id, false);
try
{
// Add timeout for safety
var task = Task.Run(() => GeneratePdfResponse(id, false));
if (task.Wait(TimeSpan.FromSeconds(30))) // 30 second timeout
{
return task.Result;
}
return StatusCode(500, "PDF generation took too long");
}
catch (Exception ex)
{
Console.WriteLine($"PDF VIEW ERROR: {ex}");
return StatusCode(500, $"Error showing PDF: {ex.Message}");
}
}
private IActionResult GeneratePdfResponse(int id, bool forceDownload)
{
Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");
// Add this temporary check at the start of GeneratePdfResponse
try
{
Console.WriteLine("Testing network connection...");
_networkAccessService.ConnectToNetworkPath();
Console.WriteLine("Network connected successfully!");
_networkAccessService.DisconnectFromNetworkShare();
}
catch (Exception ex)
{
Console.WriteLine($"NETWORK ERROR: {ex.Message}");
return StatusCode(500, $"Cannot access network: {ex.Message}");
}
try
{
// Connect to the network path
@ -256,8 +371,12 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
return StatusCode(500, $"PDF generation failed: {ex.Message}");
Console.WriteLine($"Error: {ex}");
// Include inner exception if available
string errorMessage = ex.InnerException != null
? $"{ex.Message} (Inner: {ex.InnerException.Message})"
: ex.Message;
return StatusCode(500, $"PDF generation failed: {errorMessage}");
}
finally
{

View File

@ -2,24 +2,32 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.ComponentModel;
public class NetworkShareAccess : IDisposable
{
private readonly string _networkPath;
private readonly string _username;
private readonly string _password;
private bool _isConnected = false;
// Constructor to initialize the network path, username, and password
public NetworkShareAccess(string networkPath, string username, string password)
{
_networkPath = networkPath;
_username = username;
_password = password;
// Validate and normalize the network path
_networkPath = networkPath?.Trim().Replace('/', '\\') ?? throw new ArgumentNullException(nameof(networkPath));
if (!_networkPath.StartsWith(@"\\"))
{
throw new ArgumentException("Network path must start with \\\\");
}
_username = username ?? throw new ArgumentNullException(nameof(username));
_password = password ?? throw new ArgumentNullException(nameof(password));
}
// Public method to connect to the network path
public void ConnectToNetworkPath()
{
if (_isConnected) return;
var netResource = new NetResource
{
Scope = ResourceScope.GlobalNetwork,
@ -28,59 +36,78 @@ public class NetworkShareAccess : IDisposable
RemoteName = _networkPath
};
var result = WNetAddConnection2(netResource, _password, _username, 0);//ERROR HERE
int result = WNetAddConnection2(netResource, _password, _username, 0);
if (result != 0)
{
Console.WriteLine($"Error connecting to network path: {result}");
throw new IOException($"Error connecting to network path: {result}");
string errorMessage = GetNetworkErrorDescription(result);
Console.WriteLine($"Failed to connect to {_networkPath}. Error {result}: {errorMessage}");
throw new IOException($"Failed to connect to network path. Error {result}: {errorMessage}");
}
_isConnected = true;
Console.WriteLine($"Successfully connected to {_networkPath}");
}
// Public method to disconnect from the network share
public void DisconnectFromNetworkShare()
{
// Check if the network path is connected
var buffer = new StringBuilder(512);
int bufferSize = buffer.Capacity;
int connectionStatus = WNetGetConnection(_networkPath, buffer, ref bufferSize);
if (!_isConnected) return;
if (connectionStatus != 0)
try
{
Console.WriteLine($"Network path {_networkPath} is not connected. Skipping disconnection.");
return; // Exit if the connection does not exist
int result = WNetCancelConnection2(_networkPath, 0, true);
if (result != 0)
{
string errorMessage = GetNetworkErrorDescription(result);
Console.WriteLine($"Failed to disconnect from {_networkPath}. Error {result}: {errorMessage}");
throw new IOException($"Failed to disconnect from network path. Error {result}: {errorMessage}");
}
Console.WriteLine($"Successfully disconnected from {_networkPath}");
}
// Proceed with disconnection
var result = WNetCancelConnection2(_networkPath, 0, true);
if (result != 0)
finally
{
throw new IOException($"Error disconnecting from network path: {result}");
_isConnected = false;
}
}
// Dispose method to ensure proper cleanup
public void Dispose()
{
DisconnectFromNetworkShare();
try
{
DisconnectFromNetworkShare();
}
catch (Exception ex)
{
Console.WriteLine($"Error during disposal: {ex.Message}");
// Suppress disposal errors
}
}
// P/Invoke for adding a network connection
[DllImport("mpr.dll")]
private string GetNetworkErrorDescription(int errorCode)
{
return errorCode switch
{
5 => "Access denied",
53 => "Network path not found",
67 => "Network name not found",
85 => "Network connection already exists",
86 => "Invalid password",
1219 => "Multiple connections to a server or shared resource not allowed",
_ => new Win32Exception(errorCode).Message
};
}
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
// P/Invoke for canceling a network connection
[DllImport("mpr.dll")]
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
private static extern int WNetCancelConnection2(string name, int flags, bool force);
// P/Invoke for checking if a network connection exists
[DllImport("mpr.dll")]
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
private static extern int WNetGetConnection(string localName, StringBuilder remoteName, ref int length);
// Struct for network resource
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private class NetResource
{
public ResourceScope Scope;
@ -93,33 +120,7 @@ public class NetworkShareAccess : IDisposable
public string Provider;
}
// Enum for resource scope
private enum ResourceScope
{
Connected = 1,
GlobalNetwork,
Remembered,
Recent,
Context
}
// Enum for resource type
private enum ResourceType
{
Any = 0,
Disk = 1,
Print = 2,
Reserved = 8
}
// Enum for resource display type
private enum ResourceDisplayType
{
Generic = 0x0,
Domain = 0x01,
Server = 0x02,
Share = 0x03,
File = 0x04,
Group = 0x05
}
private enum ResourceScope { Connected = 1, GlobalNetwork, Remembered, Recent, Context }
private enum ResourceType { Any = 0, Disk = 1, Print = 2, Reserved = 8 }
private enum ResourceDisplayType { Generic = 0x0, Domain = 0x01, Server = 0x02, Share = 0x03, File = 0x04, Group = 0x05 }
}

View File

@ -86,7 +86,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
column.Item()
.AlignMiddle()
.AlignCenter()
.Image("assets/images/pstw-logo.png")
.Image("wwwroot/assets/images/pstw-logo.jpg")
.FitArea();
});

View File

@ -23,7 +23,7 @@ internal class Program
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
builder.Services.AddScoped<NetworkShareAccess>(provider =>
new NetworkShareAccess("\\\\192.168.12.42\\images\\marine\\manual_tarball", "installer", "mms@pstw"));
new NetworkShareAccess(@"\\192.168.12.42\images\marine\manual_tarball", "installer", "mms@pstw"));
Log.Logger = new LoggerConfiguration()