diff --git a/Oqtane.Client/App.razor b/Oqtane.Client/App.razor index f8366e1c..c36313bb 100644 --- a/Oqtane.Client/App.razor +++ b/Oqtane.Client/App.razor @@ -45,6 +45,9 @@ [Parameter] public string RemoteIPAddress { get; set; } + [Parameter] + public string AuthorizationToken { get; set; } + private bool _initialized = false; private string _display = "display: none;"; private Installation _installation = new Installation { Success = false, Message = "" }; @@ -55,7 +58,7 @@ { SiteState.RemoteIPAddress = RemoteIPAddress; SiteState.AntiForgeryToken = AntiForgeryToken; - InstallationService.SetAntiForgeryTokenHeader(AntiForgeryToken); + SiteState.AuthorizationToken = AuthorizationToken; _installation = await InstallationService.IsInstalled(); if (_installation.Alias != null) diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 75343a49..fc404d7f 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -121,90 +121,97 @@ { _databaseName = "LocalDB"; } - LoadDatabaseConfigComponent(); - } + LoadDatabaseConfigComponent(); + } - private void DatabaseChanged(ChangeEventArgs eventArgs) - { - try - { - _databaseName = (string)eventArgs.Value; + private void DatabaseChanged(ChangeEventArgs eventArgs) + { + try + { + _databaseName = (string)eventArgs.Value; - LoadDatabaseConfigComponent(); - } - catch - { - _message = Localizer["Error.DbConfig.Load"]; - } - } + LoadDatabaseConfigComponent(); + } + catch + { + _message = Localizer["Error.DbConfig.Load"]; + } + } - private void LoadDatabaseConfigComponent() - { - var database = _databases.SingleOrDefault(d => d.Name == _databaseName); - if (database != null) - { - _databaseConfigType = Type.GetType(database.ControlType); - DatabaseConfigComponent = builder => - { - builder.OpenComponent(0, _databaseConfigType); - builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); }); - builder.CloseComponent(); - }; - } - } + private void LoadDatabaseConfigComponent() + { + var database = _databases.SingleOrDefault(d => d.Name == _databaseName); + if (database != null) + { + _databaseConfigType = Type.GetType(database.ControlType); + DatabaseConfigComponent = builder => + { + builder.OpenComponent(0, _databaseConfigType); + builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); }); + builder.CloseComponent(); + }; + } + } - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - var interop = new Interop(JSRuntime); - await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", ""); - await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head", ""); - } - } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + var interop = new Interop(JSRuntime); + await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", ""); + await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head"); + } + } - private async Task Install() - { - var connectionString = String.Empty; - if (_databaseConfig is IDatabaseConfigControl databaseConfigControl) - { - connectionString = databaseConfigControl.GetConnectionString(); - } + private async Task Install() + { + var connectionString = String.Empty; + if (_databaseConfig is IDatabaseConfigControl databaseConfigControl) + { + connectionString = databaseConfigControl.GetConnectionString(); + } - if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && _hostPassword.Length >= 6 && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@")) - { - _loadingDisplay = ""; - StateHasChanged(); + if (connectionString != "" && !string.IsNullOrEmpty(_hostUsername) && !string.IsNullOrEmpty(_hostPassword) && _hostPassword == _confirmPassword && !string.IsNullOrEmpty(_hostEmail) && _hostEmail.Contains("@")) + { + if (await UserService.ValidatePasswordAsync(_hostPassword)) + { + _loadingDisplay = ""; + StateHasChanged(); - Uri uri = new Uri(NavigationManager.Uri); + Uri uri = new Uri(NavigationManager.Uri); - var database = _databases.SingleOrDefault(d => d.Name == _databaseName); + var database = _databases.SingleOrDefault(d => d.Name == _databaseName); - var config = new InstallConfig - { - DatabaseType = database.DBType, - ConnectionString = connectionString, - Aliases = uri.Authority, - HostUsername = _hostUsername, - HostPassword = _hostPassword, - HostEmail = _hostEmail, - HostName = _hostUsername, - TenantName = TenantNames.Master, - IsNewTenant = true, - SiteName = Constants.DefaultSite, - Register = _register - }; + var config = new InstallConfig + { + DatabaseType = database.DBType, + ConnectionString = connectionString, + Aliases = uri.Authority, + HostUsername = _hostUsername, + HostPassword = _hostPassword, + HostEmail = _hostEmail, + HostName = _hostUsername, + TenantName = TenantNames.Master, + IsNewTenant = true, + SiteName = Constants.DefaultSite, + Register = _register + }; - var installation = await InstallationService.Install(config); - if (installation.Success) - { - NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true); - } - else - { - _message = installation.Message; - _loadingDisplay = "display: none;"; - } + var installation = await InstallationService.Install(config); + if (installation.Success) + { + NavigationManager.NavigateTo(uri.Scheme + "://" + uri.Authority, true); + } + else + { + _message = installation.Message; + _loadingDisplay = "display: none;"; + } + } + else + { + _message = Localizer["Message.Password.Invalid"]; + } } else { diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 3e3eb82c..6c665ba2 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -27,6 +27,6 @@ protected override void OnInitialized() { var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin"); - _pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId && !item.IsDeleted).ToList(); + _pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId).ToList(); } } diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 2bd43685..80d4f5e4 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -7,10 +7,6 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer -@if (_message != string.Empty) -{ - -} ... @@ -19,185 +15,285 @@
@Localizer["Info.SignedIn"]
-
- -
-
+ @if (!twofactor) + { +
+ +
+ } + else + { +
+ +
+ } +
@code { - private string _returnUrl = string.Empty; - private string _message = string.Empty; - private MessageType _type = MessageType.Info; - private string _username = string.Empty; - private string _password = string.Empty; - private bool _remember = false; - private bool validated = false; + private bool _allowsitelogin = true; + private bool _allowexternallogin = false; + private ElementReference login; + private bool validated = false; + private bool twofactor = false; + private string _username = string.Empty; + private ElementReference username; + private string _password = string.Empty; + private string _passwordtype = "password"; + private string _togglepassword = string.Empty; + private bool _remember = false; + private string _code = string.Empty; - private ElementReference login; - private ElementReference username; + private string _returnUrl = string.Empty; - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous; - public override List Resources => new List() + public override List Resources => new List() { new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" } }; - protected override async Task OnInitializedAsync() - { - if (PageState.QueryString.ContainsKey("returnurl")) - { - _returnUrl = PageState.QueryString["returnurl"]; - } + protected override async Task OnInitializedAsync() + { + try + { + _togglepassword = Localizer["ShowPassword"]; - if (PageState.QueryString.ContainsKey("name")) - { - _username = PageState.QueryString["name"]; - } + if (PageState.Site.Settings.ContainsKey("LoginOptions:AllowSiteLogin") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:AllowSiteLogin"])) + { + _allowsitelogin = bool.Parse(PageState.Site.Settings["LoginOptions:AllowSiteLogin"]); + } - if (PageState.QueryString.ContainsKey("token")) - { - var user = new User(); - user.SiteId = PageState.Site.SiteId; - user.Username = _username; - user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]); + if (PageState.Site.Settings.ContainsKey("ExternalLogin:ProviderType") && !string.IsNullOrEmpty(PageState.Site.Settings["ExternalLogin:ProviderType"])) + { + _allowexternallogin = true; + } - if (user != null) - { - await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username); - _message = Localizer["Success.Account.Verified"]; - } - else - { - await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username); - _message = Localizer["Message.Account.NotVerfied"]; - _type = MessageType.Warning; - } - } - } + if (PageState.QueryString.ContainsKey("returnurl")) + { + _returnUrl = PageState.QueryString["returnurl"]; + } - protected override async Task OnAfterRenderAsync(bool firstRender) - { - if (firstRender) - { - if(PageState.User == null) - { - await username.FocusAsync(); - } - } - } + if (PageState.QueryString.ContainsKey("name")) + { + _username = PageState.QueryString["name"]; + } - private async Task Login() - { - validated = true; - var interop = new Interop(JSRuntime); - if (await interop.FormValid(login)) - { - if (PageState.Runtime == Oqtane.Shared.Runtime.Server) - { - var user = new User(); - user.SiteId = PageState.Site.SiteId; - user.Username = _username; - user.Password = _password; - user = await UserService.LoginUserAsync(user, false, false); + if (PageState.QueryString.ContainsKey("token")) + { + var user = new User(); + user.SiteId = PageState.Site.SiteId; + user.Username = _username; + user = await UserService.VerifyEmailAsync(user, PageState.QueryString["token"]); - if (user.IsAuthenticated) - { - await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username); - // server-side Blazor needs to post to the Login page so that the cookies are set correctly - var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl }; - string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/"); - await interop.SubmitForm(url, fields); - } - else - { - await logger.LogError(LogFunction.Security, "Login Failed For Username {Username}", _username); - AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error); - } - } - else - { - // client-side Blazor - var user = new User(); - user.SiteId = PageState.Site.SiteId; - user.Username = _username; - user.Password = _password; - user = await UserService.LoginUserAsync(user, true, _remember); - if (user.IsAuthenticated) - { - await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username); - var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); - authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true)); - } - else - { - await logger.LogError(LogFunction.Security, "Login Failed For Username {Username}", _username); - AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error); - } - } - } - else - { - AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning); - } - } + if (user != null) + { + await logger.LogInformation(LogFunction.Security, "Email Verified For For Username {Username}", _username); + AddModuleMessage(Localizer["Success.Account.Verified"], MessageType.Info); + } + else + { + await logger.LogError(LogFunction.Security, "Email Verification Failed For Username {Username}", _username); + AddModuleMessage(Localizer["Message.Account.NotVerfied"], MessageType.Warning); + } + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Login {Error}", ex.Message); + AddModuleMessage(Localizer["Error.LoadLogin"], MessageType.Error); + } + } - private void Cancel() - { - NavigationManager.NavigateTo(_returnUrl); - } + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender && PageState.User == null) + { + await username.FocusAsync(); + } + } - private async Task Forgot() - { - if (_username != string.Empty) - { - var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId); - if (user != null) - { - await UserService.ForgotPasswordAsync(user); - await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username); - _message = Localizer["Message.ForgotUser"]; - } - else - { - _message = Localizer["Message.UserDoesNotExist"]; - _type = MessageType.Warning; - } - } - else - { - _message = Localizer["Message.ForgotPassword"]; - } + private async Task Login() + { + try + { + validated = true; + var interop = new Interop(JSRuntime); + if (await interop.FormValid(login)) + { + var user = new User { SiteId = PageState.Site.SiteId, Username = _username, Password = _password}; - StateHasChanged(); - } + if (!twofactor) + { + user = await UserService.LoginUserAsync(user, false, false); + } + else + { + user = await UserService.VerifyTwoFactorAsync(user, _code); + } + + if (user.IsAuthenticated) + { + await logger.LogInformation(LogFunction.Security, "Login Successful For Username {Username}", _username); + + if (PageState.Runtime == Oqtane.Shared.Runtime.Server) + { + // server-side Blazor needs to post to the Login page so that the cookies are set correctly + var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl }; + string url = Utilities.TenantUrl(PageState.Alias, "/pages/login/"); + await interop.SubmitForm(url, fields); + } + else + { + var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); + authstateprovider.NotifyAuthenticationChanged(); + NavigationManager.NavigateTo(NavigateUrl(_returnUrl, true)); + } + } + else + { + if (user.TwoFactorRequired) + { + twofactor = true; + validated = false; + AddModuleMessage(Localizer["Message.TwoFactor"], MessageType.Info); + } + else + { + if (!twofactor) + { + await logger.LogInformation(LogFunction.Security, "Login Failed For Username {Username}", _username); + AddModuleMessage(Localizer["Error.Login.Fail"], MessageType.Error); + } + else + { + await logger.LogInformation(LogFunction.Security, "Two Factor Verification Failed For Username {Username}", _username); + AddModuleMessage(Localizer["Error.TwoFactor.Fail"], MessageType.Error); + } + } + } + } + else + { + AddModuleMessage(Localizer["Message.Required.UserInfo"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Performing Login {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Login"], MessageType.Error); + } + } + + private void Cancel() + { + NavigationManager.NavigateTo(_returnUrl); + } + + private async Task Forgot() + { + try + { + if (_username != string.Empty) + { + var user = await UserService.GetUserAsync(_username, PageState.Site.SiteId); + if (user != null) + { + await UserService.ForgotPasswordAsync(user); + await logger.LogInformation(LogFunction.Security, "Password Reset Notification Sent For Username {Username}", _username); + AddModuleMessage(Localizer["Message.ForgotUser"], MessageType.Info); + } + else + { + AddModuleMessage(Localizer["Message.UserDoesNotExist"], MessageType.Warning); + } + } + else + { + AddModuleMessage(Localizer["Message.ForgotPassword"], MessageType.Info); + } + + StateHasChanged(); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Resetting Password {Error}", ex.Message); + AddModuleMessage(Localizer["Error.ResetPassword"], MessageType.Error); + } + } + + private void Reset() + { + twofactor = false; + _username = ""; + _password = ""; + ClearModuleMessage(); + StateHasChanged(); + } + + private async Task KeyPressed(KeyboardEventArgs e) + { + if (e.Code == "Enter" || e.Code == "NumpadEnter") + { + await Login(); + } + } + + private void TogglePassword() + { + if (_passwordtype == "password") + { + _passwordtype = "text"; + _togglepassword = Localizer["HidePassword"]; + } + else + { + _passwordtype = "password"; + _togglepassword = Localizer["ShowPassword"]; + } + } + + private void ExternalLogin() + { + NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + _returnUrl), true); + } - private async Task KeyPressed(KeyboardEventArgs e) - { - if (e.Code == "Enter" || e.Code == "NumpadEnter") - { - await Login(); - } - } } diff --git a/Oqtane.Client/Modules/Admin/Logs/Detail.razor b/Oqtane.Client/Modules/Admin/Logs/Detail.razor index 7111572e..1953a72d 100644 --- a/Oqtane.Client/Modules/Admin/Logs/Detail.razor +++ b/Oqtane.Client/Modules/Admin/Logs/Detail.razor @@ -155,7 +155,7 @@ } } - if (log.PageId != null && log.ModuleId != null) + if (log.PageId != null && log.ModuleId != null && log.ModuleId != -1) { var pagemodule = await PageModuleService.GetPageModuleAsync(log.PageId.Value, log.ModuleId.Value); if (pagemodule != null) diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 11533da8..3a1f4a67 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -252,7 +252,7 @@ _title = page.Title; _meta = page.Meta; _path = page.Path; - _pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList(); + _pageModules = PageState.Modules.Where(m => m.PageId == page.PageId).ToList(); if (string.IsNullOrEmpty(_path)) { diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index 15c37493..198e3678 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -13,6 +13,7 @@
    +   @SharedLocalizer["Name"]
diff --git a/Oqtane.Client/Modules/Admin/Register/Index.razor b/Oqtane.Client/Modules/Admin/Register/Index.razor index d33131c2..66ec29e5 100644 --- a/Oqtane.Client/Modules/Admin/Register/Index.razor +++ b/Oqtane.Client/Modules/Admin/Register/Index.razor @@ -90,9 +90,10 @@ else { SiteId = PageState.Site.SiteId, Username = _username, - DisplayName = (_displayname == string.Empty ? _username : _displayname), + Password = _password, Email = _email, - Password = _password + DisplayName = (_displayname == string.Empty ? _username : _displayname), + PhotoFileId = null }; user = await UserService.AddUserAsync(user); diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index 63f22032..252213c6 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -120,7 +120,10 @@
- +
+ + +
@@ -129,6 +132,12 @@
+
+ +
+ +
+


@@ -260,7 +269,10 @@ private string _smtpssl = "False"; private string _smtpusername = string.Empty; private string _smtppassword = string.Empty; + private string _smtppasswordtype = "password"; + private string _togglesmtppassword = string.Empty; private string _smtpsender = string.Empty; + private string _retention = string.Empty; private string _pwaisenabled; private int _pwaappiconfileid = -1; private FileManager _pwaappiconfilemanager; @@ -329,7 +341,9 @@ _smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False"); _smtpusername = SettingService.GetSetting(settings, "SMTPUsername", string.Empty); _smtppassword = SettingService.GetSetting(settings, "SMTPPassword", string.Empty); + _togglesmtppassword = Localizer["Show"]; _smtpsender = SettingService.GetSetting(settings, "SMTPSender", string.Empty); + _retention = SettingService.GetSetting(settings, "NotificationRetention", "30"); if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { @@ -479,12 +493,13 @@ site = await SiteService.UpdateSiteAsync(site); var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); - SettingService.SetSetting(settings, "SMTPHost", _smtphost, true); - SettingService.SetSetting(settings, "SMTPPort", _smtpport, true); - SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true); - SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true); - SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true); - SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true); + settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true); + settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true); + settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true); + settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true); + settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true); + settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true); + settings = SettingService.SetSetting(settings, "NotificationRetention", _retention, true); await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) @@ -605,8 +620,10 @@ await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); await logger.LogInformation("Site SMTP Settings Saved"); - await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly.")); + await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly.")); AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info); + var interop = new Interop(JSRuntime); + await interop.ScrollTo(0, 0, "smooth"); } catch (Exception ex) { @@ -616,7 +633,7 @@ } else { - AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning); + AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning); } } @@ -633,4 +650,18 @@ } if (string.IsNullOrEmpty(_defaultalias)) _defaultalias = _aliases.First().Name.Trim(); } + + private void ToggleSMTPPassword() + { + if (_smtppasswordtype == "password") + { + _smtppasswordtype = "text"; + _togglesmtppassword = Localizer["Hide"]; + } + else + { + _smtppasswordtype = "password"; + _togglesmtppassword = Localizer["Show"]; + } + } } diff --git a/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor b/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor index ef09cd2a..77878a1b 100644 --- a/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor +++ b/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor @@ -27,9 +27,27 @@
- +
- + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
@@ -38,6 +56,18 @@
+
+ +
+ +
+
+
+ +
+ +
+
@@ -69,6 +99,21 @@ + + +
+
+
+ +
+
@@ -104,12 +149,18 @@ private string _version = string.Empty; private string _clrversion = string.Empty; private string _osversion = string.Empty; - private string _serverpath = string.Empty; + private string _machinename = string.Empty; + private string _ipaddress = string.Empty; + private string _contentrootpath = string.Empty; + private string _webrootpath = string.Empty; private string _servertime = string.Empty; + private string _tickcount = string.Empty; + private string _workingset = string.Empty; private string _installationid = string.Empty; private string _detailederrors = string.Empty; private string _logginglevel = string.Empty; + private string _notificationlevel = string.Empty; private string _swagger = string.Empty; private string _packageservice = string.Empty; @@ -117,31 +168,42 @@ { _version = Constants.Version; - Dictionary systeminfo = await SystemService.GetSystemInfoAsync(); + Dictionary systeminfo = await SystemService.GetSystemInfoAsync("environment"); if (systeminfo != null) { - _clrversion = systeminfo["clrversion"]; - _osversion = systeminfo["osversion"]; - _serverpath = systeminfo["serverpath"]; - _servertime = systeminfo["servertime"] + " UTC"; - _installationid = systeminfo["installationid"]; + _clrversion = systeminfo["CLRVersion"].ToString(); + _osversion = systeminfo["OSVersion"].ToString(); + _machinename = systeminfo["MachineName"].ToString(); + _ipaddress = systeminfo["IPAddress"].ToString(); + _contentrootpath = systeminfo["ContentRootPath"].ToString(); + _webrootpath = systeminfo["WebRootPath"].ToString(); + _servertime = systeminfo["ServerTime"].ToString() + " UTC"; + _tickcount = TimeSpan.FromMilliseconds(Convert.ToInt64(systeminfo["TickCount"].ToString())).ToString(); + _workingset = (Convert.ToInt64(systeminfo["WorkingSet"].ToString()) / 1000000).ToString() + " MB"; + } - _detailederrors = systeminfo["detailederrors"]; - _logginglevel = systeminfo["logginglevel"]; - _swagger = systeminfo["swagger"]; - _packageservice = systeminfo["packageservice"]; - } - } + systeminfo = await SystemService.GetSystemInfoAsync(); + if (systeminfo != null) + { + _installationid = systeminfo["InstallationId"].ToString(); + _detailederrors = systeminfo["DetailedErrors"].ToString(); + _logginglevel = systeminfo["Logging:LogLevel:Default"].ToString(); + _notificationlevel = systeminfo["Logging:LogLevel:Notify"].ToString(); + _swagger = systeminfo["UseSwagger"].ToString(); + _packageservice = systeminfo["PackageService"].ToString(); + } + } private async Task SaveConfig() { try { - var settings = new Dictionary(); - settings.Add("detailederrors", _detailederrors); - settings.Add("logginglevel", _logginglevel); - settings.Add("swagger", _swagger); - settings.Add("packageservice", _packageservice); + var settings = new Dictionary(); + settings.Add("DetailedErrors", _detailederrors); + settings.Add("Logging:LogLevel:Default", _logginglevel); + settings.Add("Logging:LogLevel:Notify", _notificationlevel); + settings.Add("UseSwagger", _swagger); + settings.Add("PackageService", _packageservice); await SystemService.UpdateSystemInfoAsync(settings); AddModuleMessage(Localizer["Success.UpdateConfig.Restart"], MessageType.Success); } diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor index d04cc1b9..ceeb2713 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Add.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Add.razor @@ -49,7 +49,7 @@ var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); if (user != null) { - var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null); + var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body); notification = await NotificationService.AddNotificationAsync(notification); await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId); NavigationManager.NavigateTo(NavigateUrl()); diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 9f3d19ae..6bcf5f4a 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -41,6 +41,18 @@ else + @if (allowtwofactor) + { +
+ +
+ +
+
+ }
@@ -201,104 +213,125 @@ else } +

@code { - private string username = string.Empty; - private string password = string.Empty; - private string confirm = string.Empty; - private string email = string.Empty; - private string displayname = string.Empty; - private FileManager filemanager; - private int folderid = -1; - private int photofileid = -1; - private File photo = null; - private List profiles; - private Dictionary settings; - private string category = string.Empty; - private string filter = "to"; - private List notifications; + private string username = string.Empty; + private string password = string.Empty; + private string confirm = string.Empty; + private bool allowtwofactor = false; + private string twofactor = "False"; + private string email = string.Empty; + private string displayname = string.Empty; + private FileManager filemanager; + private int folderid = -1; + private int photofileid = -1; + private File photo = null; + private List profiles; + private Dictionary settings; + private string category = string.Empty; + private string filter = "to"; + private List notifications; - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.View; - protected override async Task OnParametersSetAsync() - { - try - { - if (PageState.User != null) - { - username = PageState.User.Username; - email = PageState.User.Email; - displayname = PageState.User.DisplayName; + protected override async Task OnParametersSetAsync() + { + try + { + if (PageState.Site.Settings.ContainsKey("LoginOptions:TwoFactor") && !string.IsNullOrEmpty(PageState.Site.Settings["LoginOptions:TwoFactor"])) + { + allowtwofactor = bool.Parse(PageState.Site.Settings["LoginOptions:TwoFactor"]); + } - // get user folder - var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath); - if (folder != null) - { - folderid = folder.FolderId; - } + if (PageState.User != null) + { + username = PageState.User.Username; + twofactor = PageState.User.TwoFactorRequired.ToString(); + email = PageState.User.Email; + displayname = PageState.User.DisplayName; - if (PageState.User.PhotoFileId != null) - { - photofileid = PageState.User.PhotoFileId.Value; - photo = await FileService.GetFileAsync(photofileid); - } - else - { - photofileid = -1; - photo = null; - } + // get user folder + var folder = await FolderService.GetFolderAsync(ModuleState.SiteId, PageState.User.FolderPath); + if (folder != null) + { + folderid = folder.FolderId; + } - profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId); - settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + if (PageState.User.PhotoFileId != null) + { + photofileid = PageState.User.PhotoFileId.Value; + photo = await FileService.GetFileAsync(photofileid); + } + else + { + photofileid = -1; + photo = null; + } - await LoadNotificationsAsync(); - } - else - { - AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning); - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message); - AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error); - } - } + profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId); + settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - private async Task LoadNotificationsAsync() - { - notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId); - notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList(); - } + await LoadNotificationsAsync(); + } + else + { + AddModuleMessage(Localizer["Message.User.NoLogIn"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error); + } + } - private string GetProfileValue(string SettingName, string DefaultValue) - => SettingService.GetSetting(settings, SettingName, DefaultValue); + private async Task LoadNotificationsAsync() + { + notifications = await NotificationService.GetNotificationsAsync(PageState.Site.SiteId, filter, PageState.User.UserId); + notifications = notifications.Where(item => item.DeletedBy != PageState.User.Username).ToList(); + } - private async Task Save() - { - try - { - if (username != string.Empty && email != string.Empty && ValidateProfiles()) - { - if (password == confirm) - { - var user = PageState.User; - user.Username = username; - user.Password = password; - user.Email = email; - user.DisplayName = (displayname == string.Empty ? username : displayname); - user.PhotoFileId = filemanager.GetFileId(); - if (user.PhotoFileId == -1) - { - user.PhotoFileId = null; - } + private string GetProfileValue(string SettingName, string DefaultValue) + => SettingService.GetSetting(settings, SettingName, DefaultValue); - await UserService.UpdateUserAsync(user); - await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); - await logger.LogInformation("User Profile Saved"); + private async Task Save() + { + try + { + if (username != string.Empty && email != string.Empty && ValidateProfiles()) + { + if (password == confirm) + { + var user = PageState.User; + user.Username = username; + user.Password = password; + user.TwoFactorRequired = bool.Parse(twofactor); + user.Email = email; + user.DisplayName = (displayname == string.Empty ? username : displayname); + user.PhotoFileId = filemanager.GetFileId(); + if (user.PhotoFileId == -1) + { + user.PhotoFileId = null; + } + if (user.PhotoFileId != null) + { + photofileid = user.PhotoFileId.Value; + photo = await FileService.GetFileAsync(photofileid); + } + else + { + photofileid = -1; + photo = null; + } - NavigationManager.NavigateTo(NavigateUrl()); - } + await UserService.UpdateUserAsync(user); + await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + await logger.LogInformation("User Profile Saved"); + + AddModuleMessage(Localizer["Success.Profile.Update"], MessageType.Success); + StateHasChanged(); + } else { AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning); diff --git a/Oqtane.Client/Modules/Admin/Users/Index.razor b/Oqtane.Client/Modules/Admin/Users/Index.razor index 4f017b85..650d9c54 100644 --- a/Oqtane.Client/Modules/Admin/Users/Index.razor +++ b/Oqtane.Client/Modules/Admin/Users/Index.razor @@ -55,15 +55,281 @@ else
-
- -
- +
+
+ +
+ +
-
+ @if (_providertype != "") + { +
+ +
+ +
+
+ } + else + { +
+ +
+ +
+
+ } +
+ +
+ +
+
+ @if (!string.IsNullOrEmpty(PageState.Alias.Path)) + { +
+ +
+ +
+
+ } + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+ @if (_providertype != "") + { +
+ +
+ +
+
+ } + @if (_providertype == AuthenticationProviderTypes.OpenIDConnect) + { +
+ +
+ +
+
+
+ +
+ +
+
+ } + @if (_providertype == AuthenticationProviderTypes.OAuth2) + { +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ } + @if (_providertype != "") + { +
+ +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ @if (_providertype == AuthenticationProviderTypes.OpenIDConnect) + { +
+ +
+ +
+
+ } +
+ +
+ +
+
+
+ +
+ +
+
+ } +
+
+
+ +
+
+ + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+
+

@@ -72,79 +338,156 @@ else } @code { - private List allroles; - private List userroles; - private string _search; + private List allroles; + private List userroles; + private string _search; + private string _allowregistration; + private string _allowsitelogin; + private string _twofactor; + private string _cookietype; - public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; + private string _minimumlength; + private string _uniquecharacters; + private string _requiredigit; + private string _requireupper; + private string _requirelower; + private string _requirepunctuation; + private string _maximumfailures; + private string _lockoutduration; - protected override async Task OnInitializedAsync() - { - allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - await LoadSettingsAsync(); - userroles = Search(_search); + private string _providertype; + private string _providername; + private string _authority; + private string _metadataurl; + private string _authorizationurl; + private string _tokenurl; + private string _userinfourl; + private string _clientid; + private string _clientsecret; + private string _clientsecrettype = "password"; + private string _toggleclientsecret = string.Empty; + private string _scopes; + private string _pkce; + private string _redirecturl; + private string _emailclaimtype; + private string _domainfilter; + private string _createusers; + + private string _secret; + private string _secrettype = "password"; + private string _togglesecret = string.Empty; + private string _issuer; + private string _audience; + private string _lifetime; + private string _token; + + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; + + protected override async Task OnInitializedAsync() + { + allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); + await LoadSettingsAsync(); + userroles = Search(_search); + + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); _allowregistration = PageState.Site.AllowRegistration.ToString(); - } + _allowsitelogin = SettingService.GetSetting(settings, "LoginOptions:AllowSiteLogin", "true"); + _twofactor = SettingService.GetSetting(settings, "LoginOptions:TwoFactor", "false"); + _cookietype = SettingService.GetSetting(settings, "LoginOptions:CookieType", "domain"); - private List Search(string search) - { - var results = allroles.Where(item => item.Role.Name == RoleNames.Registered || (item.Role.Name == RoleNames.Host && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))); + _minimumlength = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredLength", "6"); + _uniquecharacters = SettingService.GetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", "1"); + _requiredigit = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireDigit", "true"); + _requireupper = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireUppercase", "true"); + _requirelower = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireLowercase", "true"); + _requirepunctuation = SettingService.GetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", "true"); - if (!string.IsNullOrEmpty(_search)) - { - results = results.Where(item => - ( - item.User.Username.Contains(search, StringComparison.OrdinalIgnoreCase) || - item.User.Email.Contains(search, StringComparison.OrdinalIgnoreCase) || - item.User.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase) - ) - ); - } - return results.ToList(); - } + _maximumfailures = SettingService.GetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", "5"); + _lockoutduration = TimeSpan.Parse(SettingService.GetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", "00:05:00")).TotalMinutes.ToString(); - private async Task OnSearch() - { - userroles = Search(_search); - await UpdateSettingsAsync(); - } + _providertype = SettingService.GetSetting(settings, "ExternalLogin:ProviderType", ""); + _providername = SettingService.GetSetting(settings, "ExternalLogin:ProviderName", ""); + _authority = SettingService.GetSetting(settings, "ExternalLogin:Authority", ""); + _metadataurl = SettingService.GetSetting(settings, "ExternalLogin:MetadataUrl", ""); + _authorizationurl = SettingService.GetSetting(settings, "ExternalLogin:AuthorizationUrl", ""); + _tokenurl = SettingService.GetSetting(settings, "ExternalLogin:TokenUrl", ""); + _userinfourl = SettingService.GetSetting(settings, "ExternalLogin:UserInfoUrl", ""); + _clientid = SettingService.GetSetting(settings, "ExternalLogin:ClientId", ""); + _clientsecret = SettingService.GetSetting(settings, "ExternalLogin:ClientSecret", ""); + _toggleclientsecret = Localizer["Show"]; + _scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", ""); + _pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false"); + _redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype; + _emailclaimtype = SettingService.GetSetting(settings, "ExternalLogin:EmailClaimType", "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"); + _domainfilter = SettingService.GetSetting(settings, "ExternalLogin:DomainFilter", ""); + _createusers = SettingService.GetSetting(settings, "ExternalLogin:CreateUsers", "true"); - private async Task DeleteUser(UserRole UserRole) - { - try - { - var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId); - if (user != null) - { - await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId); - await logger.LogInformation("User Deleted {User}", UserRole.User); - allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); - userroles = Search(_search); - StateHasChanged(); - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message); - AddModuleMessage(ex.Message, MessageType.Error); - } - } + _secret = SettingService.GetSetting(settings, "JwtOptions:Secret", ""); + _togglesecret = Localizer["Show"]; + _issuer = SettingService.GetSetting(settings, "JwtOptions:Issuer", PageState.Uri.Scheme + "://" + PageState.Alias.Name); + _audience = SettingService.GetSetting(settings, "JwtOptions:Audience", ""); + _lifetime = SettingService.GetSetting(settings, "JwtOptions:Lifetime", "20"); + } - private string settingSearch = "AU-search"; + private List Search(string search) + { + var results = allroles.Where(item => item.Role.Name == RoleNames.Registered || (item.Role.Name == RoleNames.Host && UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))); - private async Task LoadSettingsAsync() - { - Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - _search = SettingService.GetSetting(settings, settingSearch, ""); - } + if (!string.IsNullOrEmpty(_search)) + { + results = results.Where(item => + ( + item.User.Username.Contains(search, StringComparison.OrdinalIgnoreCase) || + item.User.Email.Contains(search, StringComparison.OrdinalIgnoreCase) || + item.User.DisplayName.Contains(search, StringComparison.OrdinalIgnoreCase) + ) + ); + } + return results.ToList(); + } - private async Task UpdateSettingsAsync() - { - Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); - SettingService.SetSetting(settings, settingSearch, _search); - await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); - } + private async Task OnSearch() + { + userroles = Search(_search); + await UpdateSettingsAsync(); + } + + private async Task DeleteUser(UserRole UserRole) + { + try + { + var user = await UserService.GetUserAsync(UserRole.UserId, PageState.Site.SiteId); + if (user != null) + { + await UserService.DeleteUserAsync(user.UserId, PageState.Site.SiteId); + await logger.LogInformation("User Deleted {User}", UserRole.User); + allroles = await UserRoleService.GetUserRolesAsync(PageState.Site.SiteId); + userroles = Search(_search); + StateHasChanged(); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting User {User} {Error}", UserRole.User, ex.Message); + AddModuleMessage(ex.Message, MessageType.Error); + } + } + + private string settingSearch = "AU-search"; + + private async Task LoadSettingsAsync() + { + Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + _search = SettingService.GetSetting(settings, settingSearch, ""); + } + + private async Task UpdateSettingsAsync() + { + Dictionary settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId); + SettingService.SetSetting(settings, settingSearch, _search); + await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId); + } private async Task SaveSiteSettings() { @@ -153,7 +496,47 @@ else var site = PageState.Site; site.AllowRegistration = bool.Parse(_allowregistration); await SiteService.UpdateSiteAsync(site); - AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); + + var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); + settings = SettingService.SetSetting(settings, "LoginOptions:AllowSiteLogin", _allowsitelogin, false); + settings = SettingService.SetSetting(settings, "LoginOptions:TwoFactor", _twofactor, false); + settings = SettingService.SetSetting(settings, "LoginOptions:CookieType", _cookietype, true); + + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredLength", _minimumlength, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequiredUniqueChars", _uniquecharacters, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireDigit", _requiredigit, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireUppercase", _requireupper, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireLowercase", _requirelower, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Password:RequireNonAlphanumeric", _requirepunctuation, true); + + settings = SettingService.SetSetting(settings, "IdentityOptions:Lockout:MaxFailedAccessAttempts", _maximumfailures, true); + settings = SettingService.SetSetting(settings, "IdentityOptions:Lockout:DefaultLockoutTimeSpan", TimeSpan.FromMinutes(Convert.ToInt64(_lockoutduration)).ToString(), true); + + settings = SettingService.SetSetting(settings, "ExternalLogin:ProviderType", _providertype, false); + settings = SettingService.SetSetting(settings, "ExternalLogin:ProviderName", _providername, false); + settings = SettingService.SetSetting(settings, "ExternalLogin:Authority", _authority, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:MetadataUrl", _metadataurl, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:AuthorizationUrl", _authorizationurl, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:TokenUrl", _tokenurl, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:UserInfoUrl", _userinfourl, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:ClientId", _clientid, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:ClientSecret", _clientsecret, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:EmailClaimType", _emailclaimtype, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:DomainFilter", _domainfilter, true); + settings = SettingService.SetSetting(settings, "ExternalLogin:CreateUsers", _createusers, true); + + if (!string.IsNullOrEmpty(_secret) && _secret.Length < 16) _secret = (_secret + "????????????????").Substring(0, 16); + settings = SettingService.SetSetting(settings, "JwtOptions:Secret", _secret, true); + settings = SettingService.SetSetting(settings, "JwtOptions:Issuer", _issuer, true); + settings = SettingService.SetSetting(settings, "JwtOptions:Audience", _audience, true); + settings = SettingService.SetSetting(settings, "JwtOptions:Lifetime", _lifetime, true); + + await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); + await SettingService.ClearSiteSettingsCacheAsync(); + + AddModuleMessage(Localizer["Success.SaveSiteSettings"], MessageType.Success); } catch (Exception ex) { @@ -162,4 +545,51 @@ else } } + private void ProviderTypeChanged(ChangeEventArgs e) + { + _providertype = (string)e.Value; + if (_providertype == AuthenticationProviderTypes.OpenIDConnect) + { + _scopes = "openid,profile,email"; + } + else + { + _scopes = ""; + } + _redirecturl = PageState.Uri.Scheme + "://" + PageState.Alias.Name + "/signin-" + _providertype; + StateHasChanged(); + } + + private async Task CreateToken() + { + _token = await UserService.GetTokenAsync(); + } + + private void ToggleClientSecret() + { + if (_clientsecrettype == "password") + { + _clientsecrettype = "text"; + _toggleclientsecret = Localizer["Hide"]; + } + else + { + _clientsecrettype = "password"; + _toggleclientsecret = Localizer["Show"]; + } + } + + private void ToggleSecret() + { + if (_secrettype == "password") + { + _secrettype = "text"; + _togglesecret = Localizer["Hide"]; + } + else + { + _secrettype = "password"; + _togglesecret = Localizer["Show"]; + } + } } diff --git a/Oqtane.Client/Modules/Controls/FileManager.razor b/Oqtane.Client/Modules/Controls/FileManager.razor index 7cb80a1a..208e2f54 100644 --- a/Oqtane.Client/Modules/Controls/FileManager.razor +++ b/Oqtane.Client/Modules/Controls/FileManager.razor @@ -52,7 +52,7 @@ }
-
+
@if (ShowFiles && GetFileId() != -1) { diff --git a/Oqtane.Client/Modules/Controls/PermissionGrid.razor b/Oqtane.Client/Modules/Controls/PermissionGrid.razor index a8d103ef..d1777a68 100644 --- a/Oqtane.Client/Modules/Controls/PermissionGrid.razor +++ b/Oqtane.Client/Modules/Controls/PermissionGrid.razor @@ -252,7 +252,7 @@ for (int i = 0; i < _permissions.Count; i++) { permission = _permissions[i]; - List ids = permission.Permissions.Split(';').ToList(); + List ids = permission.Permissions.Split(';', StringSplitOptions.RemoveEmptyEntries).ToList(); ids.Remove("!" + RoleNames.Everyone); // remove deny all users ids.Remove("!" + RoleNames.Registered); // remove deny registered users if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index f3f06aee..b87c6a2c 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -53,9 +53,9 @@ namespace Oqtane.Modules if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script)) { var scripts = new List(); - foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script && item.Declaration != ResourceDeclaration.Global)) + foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { - scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "" }); + scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); } if (scripts.Any()) { diff --git a/Oqtane.Client/Oqtane.Client.csproj b/Oqtane.Client/Oqtane.Client.csproj index 18ae60da..22aa5a50 100644 --- a/Oqtane.Client/Oqtane.Client.csproj +++ b/Oqtane.Client/Oqtane.Client.csproj @@ -5,7 +5,7 @@ Exe 3.0 Debug;Release - 3.0.3 + 3.1.0 Oqtane Shaun Walker .NET Foundation @@ -13,7 +13,7 @@ .NET Foundation https://www.oqtane.org https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE - https://github.com/oqtane/oqtane.framework/releases/tag/v3.0.3 + https://github.com/oqtane/oqtane.framework/releases/tag/v3.1.0 https://github.com/oqtane/oqtane.framework Git Oqtane @@ -22,11 +22,12 @@ - - - + + + - + + diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index 162b9e2a..80c9fbab 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -28,8 +28,9 @@ namespace Oqtane.Client var builder = WebAssemblyHostBuilder.CreateDefault(args); var httpClient = new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)}; + builder.Services.AddSingleton(httpClient); + builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase - builder.Services.AddSingleton(httpClient); builder.Services.AddOptions(); // Register localization services diff --git a/Oqtane.Client/Resources/Installer/Installer.resx b/Oqtane.Client/Resources/Installer/Installer.resx index ecbce69e..740ba227 100644 --- a/Oqtane.Client/Resources/Installer/Installer.resx +++ b/Oqtane.Client/Resources/Installer/Installer.resx @@ -130,12 +130,15 @@ Install Now - Error loading Database Configuration Control + Error Loading Database Configuration Control - Please Enter All Required Fields. Ensure Passwords Match And Are Greater Than 5 Characters In Length. Ensure Email Address Provided Is Valid. + Please Enter All Required Fields. Ensure Passwords Match And Email Address Provided Is Valid. - + + The Password Provided Does Not Meet The Password Policy. Please Verify The Minimum Password Length And Complexity Requirements. + + Please Register Me For Major Product Updates And Security Bulletins diff --git a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx index 36ae93c3..33c9fb60 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Login/Index.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Remember Me? - Forgot Password @@ -130,10 +127,10 @@ User Account Could Not Be Verified. Please Contact Your Administrator For Further Instructions. - Login Failed. Please Remember That Passwords Are Case Sensitive And User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email. + Login Failed. Please Remember That Passwords Are Case Sensitive. If You Have Attempted To Sign In Multiple Times Unsuccessfully, Your Account Will Be Locked Out For A Period Of Time. Note That User Accounts Require Verification When They Are Initially Created So You May Wish To Check Your Email If You Are A New User. - Please Provide Your Username And Password + Please Provide All Required Fields You Are Already Signed In @@ -147,4 +144,61 @@ User Does Not Exist + + Please Enter The Secure Verification Code Which Was Sent To You By Email. + + + Verification Code + + + Verification Code: + + + Verification Failed. Please Ensure You Entered The Code Exactly In The Form Provided In Your Email. If You Wish To Request A New Verification Code Please Select The Cancel Option And Sign In Again. + + + A Secure Verification Code Has Been Sent To Your Email Address. Please Enter The Code That You Received. If You Do Not Receive The Code Or You Have Lost Access To Your Email, Please Contact Your Administrator. + + + Please Enter The Password Related To Your Account. Remember That Passwords Are Case Sensitive. If You Attempt Unsuccessfully To Log In To Your Account Multiple Times, You Will Be Locked Out For A Period Of Time. + + + Password + + + Password: + + + Specify If You Would Like To Be Signed Back In Automatically The Next Time You Visit This Site + + + Remember Me? + + + Please Enter The Username Related To Your Account + + + Username + + + Username: + + + Hide + + + Show + + + Use + + + Error Loading Login + + + Error Performing Login + + + Error Resetting Password + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index 49c4d0e7..c20813b4 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -318,10 +318,16 @@ The default alias for the site. Requests for non-default aliases will be redirected to the default alias. - + Default Alias: Aliases + + Hide + + + Show + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/SystemInfo/Index.resx b/Oqtane.Client/Resources/Modules/Admin/SystemInfo/Index.resx index e564fcf8..ed9f15b6 100644 --- a/Oqtane.Client/Resources/Modules/Admin/SystemInfo/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/SystemInfo/Index.resx @@ -129,8 +129,8 @@ Operating System Version - - Server Path + + Server Root Path Server Date/Time (in UTC) @@ -144,8 +144,8 @@ OS Version: - - Server Path: + + Root Path: Server Date/Time: @@ -231,4 +231,43 @@ Restart Application + + None + + + The Minimum Logging Level For Which Notifications Should Be Sent To Host Users. + + + Notification Level: + + + Server IP Address + + + IP Address: + + + Server Machine Name + + + Machine Name: + + + Amount Of Time The Service Has Been Available And Operational + + + Service Uptime: + + + Server Web Root Path + + + Web Path: + + + Memory Allocation Of Service (in MB) + + + Memory Allocation: + \ No newline at end of file diff --git a/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx b/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx index 294cc895..ba95f3c0 100644 --- a/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/UserProfile/Index.resx @@ -1,4 +1,4 @@ - +