using System; using System.IO; using System.Net; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Net.Http.Headers; using Oqtane.Enums; using Oqtane.Extensions; using Oqtane.Infrastructure; using Oqtane.Models; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Shared; namespace Oqtane.Pages { [AllowAnonymous] public class FilesModel : PageModel { private readonly IWebHostEnvironment _environment; private readonly IFileRepository _files; private readonly IUserPermissions _userPermissions; private readonly IUrlMappingRepository _urlMappings; private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; public FilesModel(IWebHostEnvironment environment, IFileRepository files, IUserPermissions userPermissions, IUrlMappingRepository urlMappings, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _environment = environment; _files = files; _userPermissions = userPermissions; _urlMappings = urlMappings; _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } public IActionResult OnGet(string path) { if (!string.IsNullOrEmpty(path)) { path = path.Replace("\\", "/"); var folderpath = ""; var filename = ""; bool download = false; if (Request.Query.ContainsKey("download")) { download = true; } var segments = path.Split('/'); if (segments.Length > 0) { filename = segments[segments.Length - 1].ToLower(); if (segments.Length > 1) { folderpath = string.Join("/", segments, 0, segments.Length - 1).ToLower() + "/"; } } Models.File file; if (folderpath == "id/" && int.TryParse(filename, out int fileid)) { file = _files.GetFile(fileid, false); } else { file = _files.GetFile(_alias.SiteId, folderpath, filename); } if (file != null) { if (file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.PermissionList)) { // calculate ETag using last modified date and file size var etag = Convert.ToString(file.ModifiedOn.Ticks ^ file.Size, 16); var header = ""; if (HttpContext.Request.Headers.ContainsKey(HeaderNames.IfNoneMatch)) { header = HttpContext.Request.Headers[HeaderNames.IfNoneMatch].ToString(); } if (!header.Equals(etag)) { var filepath = _files.GetFilePath(file); if (System.IO.File.Exists(filepath)) { if (download) { _syncManager.AddSyncEvent(_alias, EntityNames.File, file.FileId, "Download"); return PhysicalFile(filepath, file.GetMimeType(), file.Name); } else { HttpContext.Response.Headers.Append(HeaderNames.ETag, etag); return PhysicalFile(filepath, file.GetMimeType()); } } else { _logger.Log(LogLevel.Error, this, LogFunction.Read, "File Does Not Exist {FilePath}", filepath); HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; } } else { HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified; return Content(String.Empty); } } else { _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Access Attempt For Site {SiteId} And Path {Path}", _alias.SiteId, path); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } } else { // look for url mapping var urlMapping = _urlMappings.GetUrlMapping(_alias.SiteId, "files/" + folderpath + filename); if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) { var url = urlMapping.MappedUrl; if (!url.StartsWith("http")) { var uri = new Uri(HttpContext.Request.GetEncodedUrl()); url = uri.Scheme + "://" + uri.Authority + ((!string.IsNullOrEmpty(_alias.Path)) ? "/" + _alias.Path : "") + "/" + url; } return RedirectPermanent(url); } } } else { _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized File Access Attempt - Path Not Specified For Site {SiteId}", _alias.SiteId); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } // broken link string errorPath = Path.Combine(Utilities.PathCombine(_environment.ContentRootPath, "wwwroot/images"), "error.png"); return PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)); } } }