fix access to path
This commit is contained in:
parent
0b298c7965
commit
6ee24de227
@ -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 MMSSystemContext _context;//Used in TarBallForm and GeneratePdfResponse to query the database.
|
||||||
private readonly NetworkShareAccess _networkAccessService;//used in GetImage and GeneratePdfResponse
|
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)
|
public MarineController(MMSSystemContext context, NetworkShareAccess networkAccessService)
|
||||||
{
|
{
|
||||||
@ -77,32 +77,119 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
|||||||
|
|
||||||
public IActionResult GetImage(string fileName)
|
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
|
try
|
||||||
{
|
{
|
||||||
// Connect to the network path
|
string imagePath = Path.Combine(PhotoBasePath, sanitizedFileName);
|
||||||
_networkAccessService.ConnectToNetworkPath();
|
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);
|
Console.WriteLine($"Invalid image file at path: {imagePath}");
|
||||||
return File(imageBytes, "image/jpeg");
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error retrieving image: {ex.Message}");
|
Console.WriteLine($"Unexpected error: {ex}");
|
||||||
return StatusCode(500, "Error retrieving image.");
|
return StatusCode(500, "An unexpected error occurred while processing the image");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// Disconnect from the network path
|
try
|
||||||
_networkAccessService.DisconnectFromNetworkShare();
|
{
|
||||||
|
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)
|
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)
|
private IActionResult GeneratePdfResponse(int id, bool forceDownload)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Requested ID in {(forceDownload ? "GenerateReport" : "ViewPDF")}: {id}");
|
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
|
try
|
||||||
{
|
{
|
||||||
// Connect to the network path
|
// Connect to the network path
|
||||||
@ -256,8 +371,12 @@ namespace PSTW_CentralSystem.Areas.MMS.Controllers
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
Console.WriteLine($"Error: {ex}");
|
||||||
return StatusCode(500, $"PDF generation failed: {ex.Message}");
|
// 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
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,24 +2,32 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
public class NetworkShareAccess : IDisposable
|
public class NetworkShareAccess : IDisposable
|
||||||
{
|
{
|
||||||
private readonly string _networkPath;
|
private readonly string _networkPath;
|
||||||
private readonly string _username;
|
private readonly string _username;
|
||||||
private readonly string _password;
|
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)
|
public NetworkShareAccess(string networkPath, string username, string password)
|
||||||
{
|
{
|
||||||
_networkPath = networkPath;
|
// Validate and normalize the network path
|
||||||
_username = username;
|
_networkPath = networkPath?.Trim().Replace('/', '\\') ?? throw new ArgumentNullException(nameof(networkPath));
|
||||||
_password = password;
|
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()
|
public void ConnectToNetworkPath()
|
||||||
{
|
{
|
||||||
|
if (_isConnected) return;
|
||||||
|
|
||||||
var netResource = new NetResource
|
var netResource = new NetResource
|
||||||
{
|
{
|
||||||
Scope = ResourceScope.GlobalNetwork,
|
Scope = ResourceScope.GlobalNetwork,
|
||||||
@ -28,59 +36,78 @@ public class NetworkShareAccess : IDisposable
|
|||||||
RemoteName = _networkPath
|
RemoteName = _networkPath
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = WNetAddConnection2(netResource, _password, _username, 0);//ERROR HERE
|
int result = WNetAddConnection2(netResource, _password, _username, 0);
|
||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error connecting to network path: {result}");
|
string errorMessage = GetNetworkErrorDescription(result);
|
||||||
throw new IOException($"Error connecting to network path: {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()
|
public void DisconnectFromNetworkShare()
|
||||||
{
|
{
|
||||||
// Check if the network path is connected
|
if (!_isConnected) return;
|
||||||
var buffer = new StringBuilder(512);
|
|
||||||
int bufferSize = buffer.Capacity;
|
|
||||||
int connectionStatus = WNetGetConnection(_networkPath, buffer, ref bufferSize);
|
|
||||||
|
|
||||||
if (connectionStatus != 0)
|
try
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Network path {_networkPath} is not connected. Skipping disconnection.");
|
int result = WNetCancelConnection2(_networkPath, 0, true);
|
||||||
return; // Exit if the connection does not exist
|
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}");
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
// Proceed with disconnection
|
|
||||||
var result = WNetCancelConnection2(_networkPath, 0, true);
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
{
|
{
|
||||||
throw new IOException($"Error disconnecting from network path: {result}");
|
_isConnected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispose method to ensure proper cleanup
|
|
||||||
public void Dispose()
|
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
|
private string GetNetworkErrorDescription(int errorCode)
|
||||||
[DllImport("mpr.dll")]
|
{
|
||||||
|
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);
|
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
|
||||||
|
|
||||||
// P/Invoke for canceling a network connection
|
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
|
||||||
[DllImport("mpr.dll")]
|
|
||||||
private static extern int WNetCancelConnection2(string name, int flags, bool force);
|
private static extern int WNetCancelConnection2(string name, int flags, bool force);
|
||||||
|
|
||||||
// P/Invoke for checking if a network connection exists
|
[DllImport("mpr.dll", CharSet = CharSet.Unicode)]
|
||||||
[DllImport("mpr.dll")]
|
|
||||||
private static extern int WNetGetConnection(string localName, StringBuilder remoteName, ref int length);
|
private static extern int WNetGetConnection(string localName, StringBuilder remoteName, ref int length);
|
||||||
|
|
||||||
// Struct for network resource
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
private class NetResource
|
private class NetResource
|
||||||
{
|
{
|
||||||
public ResourceScope Scope;
|
public ResourceScope Scope;
|
||||||
@ -93,33 +120,7 @@ public class NetworkShareAccess : IDisposable
|
|||||||
public string Provider;
|
public string Provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enum for resource scope
|
private enum ResourceScope { Connected = 1, GlobalNetwork, Remembered, Recent, Context }
|
||||||
private enum ResourceScope
|
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 }
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ namespace PSTW_CentralSystem.Areas.MMS.Models.PDFGenerator
|
|||||||
column.Item()
|
column.Item()
|
||||||
.AlignMiddle()
|
.AlignMiddle()
|
||||||
.AlignCenter()
|
.AlignCenter()
|
||||||
.Image("assets/images/pstw-logo.png")
|
.Image("wwwroot/assets/images/pstw-logo.jpg")
|
||||||
.FitArea();
|
.FitArea();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ internal class Program
|
|||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
builder.Services.AddScoped<NetworkShareAccess>(provider =>
|
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()
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user