From 6a2ff369eaf5337cafecc156e5f0e871d8640afb Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Sat, 18 Dec 2021 10:35:22 -0500 Subject: [PATCH] Add support for IsPublic to all Setting types, enable Url Mapping for internal links --- Oqtane.Client/Modules/Admin/Site/Index.razor | 12 +- .../Modules/Admin/UrlMappings/Index.razor | 9 +- .../Services/Interfaces/IUrlMappingService.cs | 8 + Oqtane.Client/Services/SettingService.cs | 23 +- Oqtane.Client/Services/UrlMappingService.cs | 6 + Oqtane.Client/UI/SiteRouter.razor | 263 +++++++++--------- Oqtane.Server/Controllers/ModuleController.cs | 4 +- Oqtane.Server/Controllers/PageController.cs | 28 +- .../Controllers/SettingController.cs | 105 ++++--- Oqtane.Server/Controllers/SiteController.cs | 9 +- .../Controllers/UrlMappingController.cs | 19 +- .../Controllers/VisitorController.cs | 15 +- .../Tenant/03000201_UpdateSettingIsPublic.cs | 30 ++ Oqtane.Server/Pages/_Host.cshtml.cs | 25 +- .../Repository/UrlMappingRepository.cs | 30 +- 15 files changed, 328 insertions(+), 258 deletions(-) create mode 100644 Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index ebe7548fc..fab9fb182 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -476,12 +476,12 @@ site = await SiteService.UpdateSiteAsync(site); var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); - SettingService.SetSetting(settings, "SMTPHost", _smtphost); - SettingService.SetSetting(settings, "SMTPPort", _smtpport); - SettingService.SetSetting(settings, "SMTPSSL", _smtpssl); - SettingService.SetSetting(settings, "SMTPUsername", _smtpusername); - SettingService.SetSetting(settings, "SMTPPassword", _smtppassword); - SettingService.SetSetting(settings, "SMTPSender", _smtpsender); + SettingService.SetSetting(settings, "SMTPHost", _smtphost, false); + SettingService.SetSetting(settings, "SMTPPort", _smtpport, false); + SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, false); + SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, false); + SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, false); + SettingService.SetSetting(settings, "SMTPSender", _smtpsender, false); await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) diff --git a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor index 327f7a37c..02f41be92 100644 --- a/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor +++ b/Oqtane.Client/Modules/Admin/UrlMappings/Index.razor @@ -40,10 +40,10 @@ else - @context.Url + @context.Url @if (_mapped) { - @((MarkupString)"
>> ")@context.MappedUrl + @((MarkupString)"
>> ")@context.MappedUrl } @context.Requests @@ -96,11 +96,6 @@ else } } - private void BrowseUrl(string url) - { - NavigationManager.NavigateTo(url, true); - } - private async Task DeleteUrlMapping(UrlMapping urlMapping) { try diff --git a/Oqtane.Client/Services/Interfaces/IUrlMappingService.cs b/Oqtane.Client/Services/Interfaces/IUrlMappingService.cs index 0a8ef940a..6da0bf9d4 100644 --- a/Oqtane.Client/Services/Interfaces/IUrlMappingService.cs +++ b/Oqtane.Client/Services/Interfaces/IUrlMappingService.cs @@ -24,6 +24,14 @@ public interface IUrlMappingService /// Task GetUrlMappingAsync(int urlMappingId); + /// + /// Get one specific + /// + /// ID-reference of a + /// A url + /// + Task GetUrlMappingAsync(int siteId, string url); + /// /// Add / save a new to the database. /// diff --git a/Oqtane.Client/Services/SettingService.cs b/Oqtane.Client/Services/SettingService.cs index 2e90d66bc..e3449c056 100644 --- a/Oqtane.Client/Services/SettingService.cs +++ b/Oqtane.Client/Services/SettingService.cs @@ -131,23 +131,14 @@ public async Task UpdateSettingsAsync(Dictionary settings, strin foreach (KeyValuePair kvp in settings) { string value = kvp.Value; - bool ispublic = false; - if (value.StartsWith("[Public]")) + bool ispublic = true; + + if (value.StartsWith("[Private]")) { - switch (entityName) - { - case EntityNames.Site: - case EntityNames.ModuleDefinition: - ispublic = true; - break; - default: - ispublic = false; - break; - } - value = value.Substring(8); // remove [Public] + value = value.Substring(9); // remove [Private] + ispublic = false; } - Setting setting = settingsList.FirstOrDefault(item => item.SettingName.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase)); if (setting == null) { @@ -205,7 +196,7 @@ public string GetSetting(Dictionary settings, string settingName public Dictionary SetSetting(Dictionary settings, string settingName, string settingValue) { - return SetSetting(settings, settingName, settingValue, false); + return SetSetting(settings, settingName, settingValue, true); } public Dictionary SetSetting(Dictionary settings, string settingName, string settingValue, bool isPublic) @@ -214,7 +205,7 @@ public Dictionary SetSetting(Dictionary settings { settings = new Dictionary(); } - settingValue = (isPublic) ? "[Public]" + settingValue : settingValue; + settingValue = (isPublic) ? settingValue : "[Private]" + settingValue; if (settings.ContainsKey(settingName)) { settings[settingName] = settingValue; diff --git a/Oqtane.Client/Services/UrlMappingService.cs b/Oqtane.Client/Services/UrlMappingService.cs index 725149dcb..121e818b9 100644 --- a/Oqtane.Client/Services/UrlMappingService.cs +++ b/Oqtane.Client/Services/UrlMappingService.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Oqtane.Documentation; using Oqtane.Shared; +using System.Net; namespace Oqtane.Services { @@ -33,6 +34,11 @@ public async Task GetUrlMappingAsync(int urlMappingId) return await GetJsonAsync($"{Apiurl}/{urlMappingId}"); } + public async Task GetUrlMappingAsync(int siteId, string url) + { + return await GetJsonAsync($"{Apiurl}/url/{siteId}?url={WebUtility.UrlEncode(url)}"); + } + public async Task AddUrlMappingAsync(UrlMapping role) { return await PostJsonAsync(Apiurl, role); diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index a6a222db2..9806b6994 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -9,6 +9,7 @@ @inject IPageService PageService @inject IUserService UserService @inject IModuleService ModuleService +@inject IUrlMappingService UrlMappingService @inject ILogService LogService @implements IHandleAfterRender @@ -83,133 +84,133 @@ var querystring = ParseQueryString(route.Query); // reload the client application if there is a forced reload or the user navigated to a site with a different alias - if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path))) - { - NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true); - return; - } - else - { - // the refresh parameter is used to refresh the PageState - if (querystring.ContainsKey("refresh")) - { - refresh = UI.Refresh.Site; - } - } + if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path))) + { + NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true); + return; + } + else + { + // the refresh parameter is used to refresh the PageState + if (querystring.ContainsKey("refresh")) + { + refresh = UI.Refresh.Site; + } + } - if (PageState != null) - { - editmode = PageState.EditMode; - lastsyncdate = PageState.LastSyncDate; - } + if (PageState != null) + { + editmode = PageState.EditMode; + lastsyncdate = PageState.LastSyncDate; + } // process any sync events - var sync = await SyncService.GetSyncAsync(lastsyncdate); - lastsyncdate = sync.SyncDate; - if (sync.SyncEvents.Any()) - { - // reload client application if server was restarted or site runtime/rendermode was modified - if (PageState != null && sync.SyncEvents.Exists(item => (item.TenantId == -1 || item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId) && item.Reload)) - { - NavigationManager.NavigateTo(_absoluteUri, true); - return; - } - if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId)) - { - refresh = UI.Refresh.Site; - } - } + var sync = await SyncService.GetSyncAsync(lastsyncdate); + lastsyncdate = sync.SyncDate; + if (sync.SyncEvents.Any()) + { + // reload client application if server was restarted or site runtime/rendermode was modified + if (PageState != null && sync.SyncEvents.Exists(item => (item.TenantId == -1 || item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId) && item.Reload)) + { + NavigationManager.NavigateTo(_absoluteUri, true); + return; + } + if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId)) + { + refresh = UI.Refresh.Site; + } + } - if (refresh == UI.Refresh.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId) - { - site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId); - refresh = UI.Refresh.Site; - } - else - { - site = PageState.Site; - } + if (refresh == UI.Refresh.Site || PageState == null || PageState.Alias.SiteId != SiteState.Alias.SiteId) + { + site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId); + refresh = UI.Refresh.Site; + } + else + { + site = PageState.Site; + } - if (site != null) - { - if (PageState == null || refresh == UI.Refresh.Site) - { - // get user - var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); - if (authState.User.Identity.IsAuthenticated) - { - user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId); - user.IsAuthenticated = authState.User.Identity.IsAuthenticated; - } - } - else - { - user = PageState.User; - } + if (site != null) + { + if (PageState == null || refresh == UI.Refresh.Site) + { + // get user + var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + if (authState.User.Identity.IsAuthenticated) + { + user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId); + user.IsAuthenticated = authState.User.Identity.IsAuthenticated; + } + } + else + { + user = PageState.User; + } - // process any sync events for user - if (refresh != UI.Refresh.Site && user != null && sync.SyncEvents.Any()) - { - if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId)) - { - refresh = UI.Refresh.Site; - } - } + // process any sync events for user + if (refresh != UI.Refresh.Site && user != null && sync.SyncEvents.Any()) + { + if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId)) + { + refresh = UI.Refresh.Site; + } + } - if (PageState == null || refresh == UI.Refresh.Site) - { - pages = await PageService.GetPagesAsync(site.SiteId); - } - else - { - pages = PageState.Pages; - } + if (PageState == null || refresh == UI.Refresh.Site) + { + pages = await PageService.GetPagesAsync(site.SiteId); + } + else + { + pages = PageState.Pages; + } - if (PageState == null || refresh == UI.Refresh.Site) - { - page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); - } - else - { - page = PageState.Page; - } + if (PageState == null || refresh == UI.Refresh.Site) + { + page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); + } + else + { + page = PageState.Page; + } - // get the page if the path has changed - if (page == null || page.Path != route.PagePath) - { - page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); + // get the page if the path has changed + if (page == null || page.Path != route.PagePath) + { + page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); // if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify the home page) if (page == null && route.PagePath == "") { page = pages.FirstOrDefault(); } - editmode = false; - } + editmode = false; + } - if (page != null) - { - if (PageState == null) - { - editmode = false; - } + if (page != null) + { + if (PageState == null) + { + editmode = false; + } - // check if user is authorized to view page - if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.Permissions)) - { - page = await ProcessPage(page, site, user); + // check if user is authorized to view page + if (UserSecurity.IsAuthorized(user, PermissionNames.View, page.Permissions)) + { + page = await ProcessPage(page, site, user); - if (PageState == null || refresh == UI.Refresh.Site) - { - modules = await ModuleService.GetModulesAsync(site.SiteId); - } - else - { - modules = PageState.Modules; - } + if (PageState == null || refresh == UI.Refresh.Site) + { + modules = await ModuleService.GetModulesAsync(site.SiteId); + } + else + { + modules = PageState.Modules; + } - (page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType); + (page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType); - _pagestate = new PageState + _pagestate = new PageState { Alias = SiteState.Alias, Site = site, @@ -228,25 +229,33 @@ VisitorId = VisitorId }; - OnStateChange?.Invoke(_pagestate); - } - } - else - { - if (user == null) - { - // redirect to login page - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath)); - } - else - { - await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath); - if (route.PagePath != "") - { - // redirect to home page - NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); - } - } + OnStateChange?.Invoke(_pagestate); + } + } + else // page not found + { + var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.SiteUrl + "/" + route.PagePath); + if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) + { + NavigationManager.NavigateTo(urlMapping.MappedUrl, false); + } + else // not mapped + { + if (user == null) + { + // redirect to login page if user not logged in as they may need to be authenticated + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath)); + } + else + { + await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath); + if (route.PagePath != "") + { + // redirect to home page + NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", "")); + } + } + } } } else diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index 727523cb3..cfcad9703 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -75,6 +75,7 @@ public IEnumerable Get(string siteid) module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName); module.Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId) + .Where(item => item.IsPublic || _userPermissions.IsAuthorized(User, PermissionNames.Edit, pagemodule.Module.Permissions)) .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); modules.Add(module); @@ -101,7 +102,8 @@ public Module Get(int id) List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(module.SiteId).ToList(); module.ModuleDefinition = moduledefinitions.Find(item => item.ModuleDefinitionName == module.ModuleDefinitionName); module.Settings = _settings.GetSettings(EntityNames.Module, id) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + .Where(item => item.IsPublic || _userPermissions.IsAuthorized(User, PermissionNames.Edit, module.Permissions)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); return module; } else diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index cd83718af..5f792dd8e 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -57,6 +57,7 @@ public IEnumerable Get(string siteid) if (_userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions)) { page.Settings = settings.Where(item => item.EntityId == page.PageId) + .Where(item => item.IsPublic || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions)) .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); pages.Add(page); } @@ -85,15 +86,16 @@ public Page Get(int id, string userid) { page = _pages.GetPage(id, int.Parse(userid)); } - if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions)) + if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions)) { page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + .Where(item => item.IsPublic || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); return page; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {PageId} {UserId}", id, userid); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } @@ -104,24 +106,16 @@ public Page Get(int id, string userid) public Page Get(string path, int siteid) { Page page = _pages.GetPage(WebUtility.UrlDecode(path), siteid); - if (page != null && page.SiteId == _alias.SiteId) + if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, page.Permissions)) { - if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions)) - { - page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId) - .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); - return page; - } - else - { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Page}", page); - HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; - return null; - } + page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId) + .Where(item => item.IsPublic || _userPermissions.IsAuthorized(User, PermissionNames.Edit, page.Permissions)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + return page; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {Path} for Site {SiteId}", path, siteid); + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Page Get Attempt {SiteId} {Path}", siteid, path); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 33e485894..fb5776842 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -20,6 +20,7 @@ public class SettingController : Controller private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; + private readonly string _visitorCookie; public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { @@ -29,39 +30,25 @@ public SettingController(ISettingRepository settings, IPageModuleRepository page _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); + _visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString(); } // GET: api/ [HttpGet] - public IEnumerable Get(string entityName, int entityid) + public IEnumerable Get(string entityName, int entityId) { List settings = new List(); - if (IsAuthorized(entityName, entityid, PermissionNames.View)) + if (IsAuthorized(entityName, entityId, PermissionNames.View)) { - settings = _settings.GetSettings(entityName, entityid).ToList(); - - // ispublic filter - switch (entityName) + settings = _settings.GetSettings(entityName, entityId).ToList(); + if (FilterPublic(entityName, entityId)) { - case EntityNames.Tenant: - case EntityNames.ModuleDefinition: - case EntityNames.Host: - if (!User.IsInRole(RoleNames.Host)) - { - settings = settings.Where(item => item.IsPublic).ToList(); - } - break; - case EntityNames.Site: - if (!User.IsInRole(RoleNames.Admin)) - { - settings = settings.Where(item => item.IsPublic).ToList(); - } - break; + settings = settings.Where(item => item.IsPublic).ToList(); } } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityName, entityid); + _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Settings {EntityName} {EntityId}", entityName, entityId); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; } return settings; @@ -74,30 +61,15 @@ public Setting Get(int id, string entityName) Setting setting = _settings.GetSetting(entityName, id); if (IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.View)) { - // ispublic filter - switch (entityName) + if (FilterPublic(entityName, id) && !setting.IsPublic) { - case EntityNames.Tenant: - case EntityNames.ModuleDefinition: - case EntityNames.Host: - if (!User.IsInRole(RoleNames.Host) && !setting.IsPublic) - { - setting = null; - } - break; - case EntityNames.Site: - if (!User.IsInRole(RoleNames.Admin) && !setting.IsPublic) - { - setting = null; - } - break; + setting = null; } - return setting; } else { - _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {Setting}", setting); + _logger.Log(LogLevel.Error, this, LogFunction.Read, "User Not Authorized To Access Setting {EntityName} {SettingId}", entityName, id); HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; return null; } @@ -204,20 +176,67 @@ private bool IsAuthorized(string entityName, int entityId, string permissionName } break; case EntityNames.Visitor: - var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString(); - if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId)) + authorized = User.IsInRole(RoleNames.Admin); + if (!authorized) + { + if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId)) + { + authorized = (visitorId == entityId); + } + } + break; + default: // custom entity + if (permissionName == PermissionNames.Edit) { - authorized = (visitorId == entityId); + authorized = User.IsInRole(RoleNames.Admin); } else { - authorized = User.IsInRole(RoleNames.Admin); + authorized = true; } break; } return authorized; } + private bool FilterPublic(string entityName, int entityId) + { + bool filter = false; + switch (entityName) + { + case EntityNames.Tenant: + case EntityNames.ModuleDefinition: + case EntityNames.Host: + filter = !User.IsInRole(RoleNames.Host); + break; + case EntityNames.Site: + filter = !User.IsInRole(RoleNames.Admin); + break; + case EntityNames.Page: + case EntityNames.Module: + case EntityNames.Folder: + filter = !_userPermissions.IsAuthorized(User, entityName, entityId, PermissionNames.Edit); + break; + case EntityNames.User: + filter = !User.IsInRole(RoleNames.Admin) && _userPermissions.GetUser(User).UserId != entityId; + break; + case EntityNames.Visitor: + if (!User.IsInRole(RoleNames.Admin)) + { + filter = true; + if (int.TryParse(Request.Cookies[_visitorCookie], out int visitorId)) + { + filter = (visitorId != entityId); + } + } + break; + default: // custom entity + filter = !User.IsInRole(RoleNames.Admin); + break; + } + return filter; + } + private void AddSyncEvent(string EntityName) { switch (EntityName) diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 6b4d1c7bf..1ff066a84 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -44,12 +44,9 @@ public Site Get(int id) var site = _sites.GetSite(id); if (site.SiteId == _alias.SiteId) { - var settings = _settings.GetSettings(EntityNames.Site, site.SiteId); - if (!User.IsInRole(RoleNames.Admin)) - { - settings = settings.Where(item => item.IsPublic); - } - site.Settings = settings.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); + site.Settings = _settings.GetSettings(EntityNames.Site, site.SiteId) + .Where(item => item.IsPublic || User.IsInRole(RoleNames.Admin)) + .ToDictionary(setting => setting.SettingName, setting => setting.SettingValue); return site; } else diff --git a/Oqtane.Server/Controllers/UrlMappingController.cs b/Oqtane.Server/Controllers/UrlMappingController.cs index d3a0ea53e..9e8c745c2 100644 --- a/Oqtane.Server/Controllers/UrlMappingController.cs +++ b/Oqtane.Server/Controllers/UrlMappingController.cs @@ -48,7 +48,7 @@ public IEnumerable Get(string siteid, string ismapped) public UrlMapping Get(int id) { var urlMapping = _urlMappings.GetUrlMapping(id); - if (urlMapping != null && (urlMapping.SiteId == _alias.SiteId)) + if (urlMapping != null && urlMapping.SiteId == _alias.SiteId) { return urlMapping; } @@ -60,6 +60,23 @@ public UrlMapping Get(int id) } } + // GET api//url/x?url=y + [HttpGet("url/{siteid}")] + public UrlMapping Get(int siteid, string url) + { + var urlMapping = _urlMappings.GetUrlMapping(siteid, WebUtility.UrlDecode(url)); + if (urlMapping != null && urlMapping.SiteId == _alias.SiteId) + { + return urlMapping; + } + else + { + _logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized UrlMapping Get Attempt {SiteId} {Url}", siteid, url); + HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + return null; + } + } + // POST api/ [HttpPost] [Authorize(Roles = RoleNames.Admin)] diff --git a/Oqtane.Server/Controllers/VisitorController.cs b/Oqtane.Server/Controllers/VisitorController.cs index 3f789efd6..dfb9a63c6 100644 --- a/Oqtane.Server/Controllers/VisitorController.cs +++ b/Oqtane.Server/Controllers/VisitorController.cs @@ -47,15 +47,14 @@ public IEnumerable Get(string siteid, string fromdate) [HttpGet("{id}")] public Visitor Get(int id) { - bool authorized; - var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString(); - if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId)) + bool authorized = User.IsInRole(RoleNames.Admin); + if (!authorized) { - authorized = (visitorId == id); - } - else - { - authorized = User.IsInRole(RoleNames.Admin); + var visitorCookie = "APP_VISITOR_" + _alias.SiteId.ToString(); + if (int.TryParse(Request.Cookies[visitorCookie], out int visitorId)) + { + authorized = (visitorId == id); + } } var visitor = _visitors.GetVisitor(id); diff --git a/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs b/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs new file mode 100644 index 000000000..7599ffd10 --- /dev/null +++ b/Oqtane.Server/Migrations/Tenant/03000201_UpdateSettingIsPublic.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Oqtane.Databases.Interfaces; +using Oqtane.Migrations.EntityBuilders; +using Oqtane.Repository; +using Oqtane.Shared; + +namespace Oqtane.Migrations.Tenant +{ + [DbContext(typeof(TenantDBContext))] + [Migration("Tenant.03.00.02.01")] + public class UpdateSettingIsPublic : MultiDatabaseMigration + { + public UpdateSettingIsPublic(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); + settingEntityBuilder.UpdateColumn("IsPublic", "1", "bool", "SettingName NOT LIKE 'SMTP%'"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var settingEntityBuilder = new SettingEntityBuilder(migrationBuilder, ActiveDatabase); + settingEntityBuilder.UpdateColumn("IsPublic", "0", "bool", "SettingName NOT LIKE 'SMTP%'"); + } + } +} diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 8c878dc65..8a89763b8 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -130,30 +130,9 @@ public IActionResult OnGet() // page does not exist var url = route.SiteUrl + "/" + route.PagePath; var urlMapping = _urlMappings.GetUrlMapping(site.SiteId, url); - if (urlMapping == null) + if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) { - if (site.CaptureBrokenUrls) - { - urlMapping = new UrlMapping(); - urlMapping.SiteId = site.SiteId; - urlMapping.Url = url; - urlMapping.MappedUrl = ""; - urlMapping.Requests = 1; - urlMapping.CreatedOn = DateTime.UtcNow; - urlMapping.RequestedOn = DateTime.UtcNow; - _urlMappings.AddUrlMapping(urlMapping); - } - } - else - { - urlMapping.Requests += 1; - urlMapping.RequestedOn = DateTime.UtcNow; - _urlMappings.UpdateUrlMapping(urlMapping); - - if (!string.IsNullOrEmpty(urlMapping.MappedUrl)) - { - return RedirectPermanent(urlMapping.MappedUrl); - } + return RedirectPermanent(urlMapping.MappedUrl); } } } diff --git a/Oqtane.Server/Repository/UrlMappingRepository.cs b/Oqtane.Server/Repository/UrlMappingRepository.cs index 306d8f69c..debb3a2f7 100644 --- a/Oqtane.Server/Repository/UrlMappingRepository.cs +++ b/Oqtane.Server/Repository/UrlMappingRepository.cs @@ -9,12 +9,14 @@ namespace Oqtane.Repository public class UrlMappingRepository : IUrlMappingRepository { private TenantDBContext _db; + private readonly ISiteRepository _sites; - public UrlMappingRepository(TenantDBContext context) + public UrlMappingRepository(TenantDBContext context, ISiteRepository sites) { _db = context; + _sites = sites; } - + public IEnumerable GetUrlMappings(int siteId, bool isMapped) { if (isMapped) @@ -60,7 +62,29 @@ public UrlMapping GetUrlMapping(int urlMappingId, bool tracking) public UrlMapping GetUrlMapping(int siteId, string url) { - return _db.UrlMapping.Where(item => item.SiteId == siteId && item.Url == url).FirstOrDefault(); + var urlMapping = _db.UrlMapping.Where(item => item.SiteId == siteId && item.Url == url).FirstOrDefault(); + if (urlMapping == null) + { + var site = _sites.GetSite(siteId); + if (site.CaptureBrokenUrls) + { + urlMapping = new UrlMapping(); + urlMapping.SiteId = siteId; + urlMapping.Url = url; + urlMapping.MappedUrl = ""; + urlMapping.Requests = 1; + urlMapping.CreatedOn = DateTime.UtcNow; + urlMapping.RequestedOn = DateTime.UtcNow; + urlMapping = AddUrlMapping(urlMapping); + } + } + else + { + urlMapping.Requests += 1; + urlMapping.RequestedOn = DateTime.UtcNow; + urlMapping = UpdateUrlMapping(urlMapping); + } + return urlMapping; } public void DeleteUrlMapping(int urlMappingId)