From eba44b46e2e0c9cc04d2a218bab1f3dca630d266 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 15:51:55 +0100 Subject: [PATCH 1/7] postit: allow self-signed OIDC TLS in Development --- src/PostIt/PostIt/ViewModels/Settings.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/PostIt/PostIt/ViewModels/Settings.cs b/src/PostIt/PostIt/ViewModels/Settings.cs index 5bd3a844..9d556712 100644 --- a/src/PostIt/PostIt/ViewModels/Settings.cs +++ b/src/PostIt/PostIt/ViewModels/Settings.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; using System.Text.Json; using System.Threading; @@ -182,6 +183,16 @@ public partial class Settings : ViewModelBase // PKCE is enabled by default when no client_secret is provided. }; + if (IsDevelopmentEnvironment()) + { + // Dev only: allow local/self-signed TLS for discovery/token + // endpoints when the machine does not trust a custom root. + options.BackchannelHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (_, _, _, _) => true + }; + } + if (browser is not null) options.Browser = browser; @@ -231,6 +242,14 @@ public partial class Settings : ViewModelBase } } + private static bool IsDevelopmentEnvironment() + { + return string.Equals( + Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), + "Development", + StringComparison.OrdinalIgnoreCase); + } + internal void Load() { if (Loaded) return; -- 2.47.3 From 13964b9f7f2de228aac7966d1bf8d976eea78d83 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 16:07:28 +0100 Subject: [PATCH 2/7] org: show full error details in development --- src/Yavsc.Org/Views/Shared/Error.cshtml | 39 +++++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Yavsc.Org/Views/Shared/Error.cshtml b/src/Yavsc.Org/Views/Shared/Error.cshtml index ed29d328..49c7539f 100644 --- a/src/Yavsc.Org/Views/Shared/Error.cshtml +++ b/src/Yavsc.Org/Views/Shared/Error.cshtml @@ -1,14 +1,41 @@ -@model ErrorViewModel +@using Microsoft.AspNetCore.Hosting +@using Yavsc.Models +@inject IWebHostEnvironment Env +@model object @{ ViewBag.Title = "Error"; }

Error.

-

An error occurred while processing your request.

-@if (Model!=null) if (Model.ShowRequestId) +@if (Env.IsDevelopment()) { -

- Request ID: @Model.RequestId -

+

An unhandled exception occurred while processing your request.

+ if (Model is Exception exception) + { +
@exception.ToString()
+ } + else if (Model is ErrorViewModel errorViewModel && !string.IsNullOrWhiteSpace(errorViewModel.Description)) + { +
@errorViewModel.Description
+ } +} +else +{ +

An error occurred while processing your request.

+ + if (Model is ErrorViewModel errorViewModel) + { + if (errorViewModel.ShowRequestId) + { +

+ Request ID: @errorViewModel.RequestId +

+ } + + if (!string.IsNullOrWhiteSpace(errorViewModel.Description)) + { +

@errorViewModel.Description

+ } + } } -- 2.47.3 From 3d80a3f2a17af9aa0ffca960c478b50ae02e95e2 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 16:14:37 +0100 Subject: [PATCH 3/7] Post logout redirect uri --- .vscode/settings.json | 1 + src/PostIt/PostIt/ViewModels/Settings.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6e22cb5e..dc0a5a77 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,6 +14,7 @@ "envsubst", "Newtonsoft", "Npgsql", + "PKCE", "postit", "pschneider", "SLNDIR", diff --git a/src/PostIt/PostIt/ViewModels/Settings.cs b/src/PostIt/PostIt/ViewModels/Settings.cs index 9d556712..890ca15c 100644 --- a/src/PostIt/PostIt/ViewModels/Settings.cs +++ b/src/PostIt/PostIt/ViewModels/Settings.cs @@ -179,7 +179,7 @@ public partial class Settings : ViewModelBase RedirectUri = Authentication.RedirectUri, Scope = string.Join(' ', MergeScopes(this.Authentication.Scopes)), TokenClientCredentialStyle = IdentityModel.Client.ClientCredentialStyle.PostBody, - PostLogoutRedirectUri = "https//yavsc.pschneider.fr", + PostLogoutRedirectUri = Authentication.Authority, // PKCE is enabled by default when no client_secret is provided. }; -- 2.47.3 From 9622dbeaf2c901585364ed276f2cd33d80cb15da Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 16:26:43 +0100 Subject: [PATCH 4/7] Hsts --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index dc0a5a77..16bbe483 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,6 +12,7 @@ "DOTNET", "ecdsa", "envsubst", + "Hsts", "Newtonsoft", "Npgsql", "PKCE", -- 2.47.3 From fda43ba2d1a0fbcb1fde803a0d87aceecb3530ce Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 16:27:13 +0100 Subject: [PATCH 5/7] Hsts --- src/Yavsc.Org/Extensions/HostingExtensions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index a494a05b..74a1a53e 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -972,7 +972,8 @@ public static class HostingExtensions else { app.UseExceptionHandler("/Home/Error"); - logger.LogInformation("Running in production mode. Ensure the database is migrated."); + app.UseHsts(); + logger.LogInformation("⨝ Running in production mode. Ensure the database is migrated."); await app.MigrateDatabaseAsync(); } -- 2.47.3 From 786016344b0a63b2f105e14cb96bf5bd3b25055a Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 12 Jul 2026 17:56:23 +0100 Subject: [PATCH 6/7] refacto error handling --- .../Accounting/AccountController.cs | 10 ++-- .../Accounting/ManageController.cs | 14 ----- .../Controllers/Consent/ConsentController.cs | 17 +++--- .../Controllers/Device/DeviceController.cs | 20 ++++++- src/Yavsc.Org/Controllers/HomeController.cs | 56 +++++++++++++++---- src/Yavsc.Org/Extensions/HostingExtensions.cs | 1 - src/Yavsc.Org/Helpers/ErrorViewHelpers.cs | 52 +++++++++++++++++ src/Yavsc.Server/Models/ErrorViewModel.cs | 1 + 8 files changed, 126 insertions(+), 45 deletions(-) create mode 100644 src/Yavsc.Org/Helpers/ErrorViewHelpers.cs diff --git a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs index e8a63163..43565442 100644 --- a/src/Yavsc.Org/Controllers/Accounting/AccountController.cs +++ b/src/Yavsc.Org/Controllers/Accounting/AccountController.cs @@ -791,12 +791,12 @@ IHtmlLocalizerFactory htmlLocalizerFactory, { if (userId == null || code == null) { - return View("Error"); + return this.ErrorView("Error: userId or code is null."); } var user = await _userManager.FindByIdAsync(userId); if (user == null) { - return View("Error"); + return this.ErrorView("Error: user not found."); } IdentityResult result = null; try @@ -819,12 +819,12 @@ IHtmlLocalizerFactory htmlLocalizerFactory, { if (userId == null || code == null) { - return View("Error"); + return this.ErrorView("Error: userId or code is null."); } var user = await _userManager.FindByIdAsync(userId); if (user == null) { - return View("Error"); + return this.ErrorView("Error: user not found."); } bool result = false; try @@ -837,7 +837,7 @@ IHtmlLocalizerFactory htmlLocalizerFactory, _logger.LogError(ex.StackTrace); _logger.LogError(ex.Message); } - return View(result ? "EmailConfirmed" : "Error"); + return result ? View("EmailConfirmed") : this.ErrorView("Error confirming two factor token."); } // diff --git a/src/Yavsc.Org/Controllers/Accounting/ManageController.cs b/src/Yavsc.Org/Controllers/Accounting/ManageController.cs index 7419c889..43e11cd2 100644 --- a/src/Yavsc.Org/Controllers/Accounting/ManageController.cs +++ b/src/Yavsc.Org/Controllers/Accounting/ManageController.cs @@ -1,6 +1,5 @@ using System.Security.Claims; -using System.IO; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Localization; @@ -490,12 +489,7 @@ namespace Yavsc.Controllers : message == ManageMessageId.Error ? "An error has occurred." : ""; var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } var userLogins = await _userManager.GetLoginsAsync(user); - ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; return View(new ManageLoginsViewModel @@ -522,15 +516,7 @@ namespace Yavsc.Controllers public async Task LinkLoginCallback() { var user = await GetCurrentUserAsync(); - if (user == null) - { - return View("Error"); - } var info = await _signInManager.GetExternalLoginInfoAsync(User.GetUserId()); - if (info == null) - { - return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error }); - } var result = await _userManager.AddLoginAsync(user, info); var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error; return RedirectToAction(nameof(ManageLogins), new { Message = message }); diff --git a/src/Yavsc.Org/Controllers/Consent/ConsentController.cs b/src/Yavsc.Org/Controllers/Consent/ConsentController.cs index 15c4a93b..b7b6eff8 100644 --- a/src/Yavsc.Org/Controllers/Consent/ConsentController.cs +++ b/src/Yavsc.Org/Controllers/Consent/ConsentController.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using System; using Yavsc; using Yavsc.Extensions; +using Yavsc.Models; namespace IdentityServerHost.Quickstart.UI { @@ -53,10 +54,11 @@ namespace IdentityServerHost.Quickstart.UI { return View("Index", vm); } - - return View("Error"); + return this.ErrorView("No consent request matching request: " + returnUrl); } + + /// /// Handles the consent screen postback /// @@ -88,8 +90,8 @@ namespace IdentityServerHost.Quickstart.UI { return View("Index", result.ViewModel); } - - return View("Error"); + return this.ErrorView($"ReturnUrl: {model}, result: {result}" ); + } /*****************************************/ @@ -170,11 +172,6 @@ namespace IdentityServerHost.Quickstart.UI { return CreateConsentViewModel(model, returnUrl, request); } - else - { - _logger.LogError("No consent request matching request: {0}", returnUrl); - } - return null; } @@ -199,7 +196,7 @@ namespace IdentityServerHost.Quickstart.UI vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray(); var apiScopes = new List(); - foreach(var parsedScope in request.ValidatedResources.ParsedScopes) + foreach (var parsedScope in request.ValidatedResources.ParsedScopes) { var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName); if (apiScope != null) diff --git a/src/Yavsc.Org/Controllers/Device/DeviceController.cs b/src/Yavsc.Org/Controllers/Device/DeviceController.cs index 5e0c7780..2e516aa6 100644 --- a/src/Yavsc.Org/Controllers/Device/DeviceController.cs +++ b/src/Yavsc.Org/Controllers/Device/DeviceController.cs @@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using Yavsc.Models; using Yavsc.Models.Access; namespace Yavsc.Controllers @@ -49,7 +50,7 @@ namespace Yavsc.Controllers if (string.IsNullOrWhiteSpace(userCode)) return View("UserCodeCapture"); var vm = await BuildViewModelAsync(userCode); - if (vm == null) return View("Error"); + if (vm == null) return this.ErrorView($"ViewModel is null! userCodeParamName: {userCodeParamName}, userCode: {userCode}" );; vm.ConfirmUserCode = true; return View("UserCodeConfirmation", vm); @@ -60,7 +61,7 @@ namespace Yavsc.Controllers public async Task UserCodeCapture(string userCode) { var vm = await BuildViewModelAsync(userCode); - if (vm == null) return View("Error"); + if (vm == null) return this.ErrorView($"UserCodeCapture: ViewModel is null! userCode: {userCode}" ); return View("UserCodeConfirmation", vm); } @@ -72,7 +73,20 @@ namespace Yavsc.Controllers if (model == null) throw new ArgumentNullException(nameof(model)); var result = await ProcessConsent(model); - if (result.HasValidationError) return View("Error"); + if (result.HasValidationError) + { + if (HttpContext.RequestServices.GetRequiredService().IsDevelopment()) + { + throw new InvalidOperationException("Device Authorization Input validation error: " + result.ValidationError); + } + + return View("Error", + new ErrorViewModel { + RequestId = HttpContext.TraceIdentifier, + Description = "Device Authorization Input validation error: " + result.ValidationError + } + ); + } return View("Success"); } diff --git a/src/Yavsc.Org/Controllers/HomeController.cs b/src/Yavsc.Org/Controllers/HomeController.cs index 2602a1a3..67c19fed 100644 --- a/src/Yavsc.Org/Controllers/HomeController.cs +++ b/src/Yavsc.Org/Controllers/HomeController.cs @@ -15,18 +15,24 @@ namespace Yavsc.Controllers public class HomeController : Controller { readonly ApplicationDbContext _dbContext; - + readonly ILogger _logger; + private readonly bool _isDevelopment; readonly IHtmlLocalizer _localizer; private SiteSettings siteSettings; public HomeController(ILogger logger, IHtmlLocalizer localizer, ApplicationDbContext context, - IOptions settingsOptions) + IOptions settingsOptions, + IWebHostEnvironment env + ) { _localizer = localizer; _dbContext = context; siteSettings = settingsOptions.Value; + _logger = logger; + _isDevelopment = env.IsDevelopment(); + } public async Task Index(string id) @@ -99,18 +105,44 @@ namespace Yavsc.Controllers public IActionResult Error() { - var feature = this.HttpContext.Features.Get(); - if (feature == null) return View(); - var errorType = feature?.Error; - if (errorType == null) return View(); - if (errorType is NotSupportedException notSupported) + if (_isDevelopment) { - return View(new ErrorViewModel { - Description = notSupported.Message, - RequestId = this.HttpContext.TraceIdentifier - }); + _logger.LogInformation( + "Home/Error requested in Development. This endpoint is disabled because DeveloperExceptionPage should handle unhandled exceptions."); + + return NotFound( + "In Development, /Home/Error is disabled. Unhandled exceptions are rendered by DeveloperExceptionPage."); } - return View("~/Views/Shared/Error.cshtml", feature?.Error); + + var errorViewModel = new ErrorViewModel + { + RequestId = HttpContext.TraceIdentifier + }; + + var exceptionHandlerPathFeature = + HttpContext.Features.Get(); + + if (exceptionHandlerPathFeature is null) + { + _logger.LogWarning( + "Home/Error called without IExceptionHandlerPathFeature in non-development environment."); + + return View("~/Views/Shared/Error.cshtml", errorViewModel); + } + + if (exceptionHandlerPathFeature?.Error is FileNotFoundException) + { + errorViewModel.Description = "The file was not found."; + } + + if (exceptionHandlerPathFeature?.Path == "/") + { + errorViewModel.Description ??= string.Empty; + errorViewModel.Description += " Page: Home."; + } + + + return View("~/Views/Shared/Error.cshtml", errorViewModel); } public IActionResult Status(int id) { diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs index 74a1a53e..b3f90639 100644 --- a/src/Yavsc.Org/Extensions/HostingExtensions.cs +++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs @@ -967,7 +967,6 @@ public static class HostingExtensions if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); - await app.MigrateDatabaseAsync(); } else { diff --git a/src/Yavsc.Org/Helpers/ErrorViewHelpers.cs b/src/Yavsc.Org/Helpers/ErrorViewHelpers.cs new file mode 100644 index 00000000..3d038c3f --- /dev/null +++ b/src/Yavsc.Org/Helpers/ErrorViewHelpers.cs @@ -0,0 +1,52 @@ +using Microsoft.AspNetCore.Mvc; +using Yavsc.Models; + +public static class ErrorViewHelpers +{ + public static IActionResult ErrorView(this Controller controller, string message) + { + var logger = controller.HttpContext.RequestServices.GetRequiredService() + .CreateLogger(); + + logger.LogError(message); + Dictionary dictionary = new Dictionary(); + + if (!controller.ModelState.IsValid) + { + foreach (var modelState in controller.ModelState.Values) + { + foreach (var error in modelState.Errors) + { + logger.LogError("ModelState error: {0}", error.ErrorMessage); + foreach (var key in controller.ModelState.Keys) + { + logger.LogError("ModelState key: {0}", key); + dictionary.Add(key, + string.Join("\n", + controller.ModelState[key].Errors.Select( e => e.ErrorMessage).ToArray())); + } + } + } + } + + if (controller.HttpContext.Request.Headers.ContainsKey("Accept") + && controller.HttpContext.Request.Headers["Accept"].ToString().Contains("application/json")) + { + return controller.Json(new + { + RequestId = controller.HttpContext.TraceIdentifier, + Description = message, + ModelErrors = dictionary + }); + } + + return controller.View("Error", + new ErrorViewModel + { + RequestId = controller.HttpContext.TraceIdentifier, + Description = message, + ModelErrors = dictionary + } + ); + } +} \ No newline at end of file diff --git a/src/Yavsc.Server/Models/ErrorViewModel.cs b/src/Yavsc.Server/Models/ErrorViewModel.cs index 1b779ead..17819476 100644 --- a/src/Yavsc.Server/Models/ErrorViewModel.cs +++ b/src/Yavsc.Server/Models/ErrorViewModel.cs @@ -7,4 +7,5 @@ public class ErrorViewModel public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + public Dictionary ModelErrors { get; set; } } -- 2.47.3 From 286c29f4e3594123d286fba7da90a4db9d1d97a8 Mon Sep 17 00:00:00 2001 From: Paul Schneider Date: Sun, 2 Aug 2026 21:08:25 +0100 Subject: [PATCH 7/7] Navigate to Main Page --- src/PostIt/PostIt/App.axaml.cs | 22 +++++++++---------- .../PostIt/ViewModels/HomePageViewModel.cs | 5 +++-- src/PostIt/PostIt/Views/HomePage.axaml | 8 +++++++ src/PostIt/PostIt/Views/InitialPage.cs | 0 src/PostIt/PostIt/Views/MainPage.axaml | 3 +-- src/PostIt/PostIt/Views/MainWindow.axaml | 2 +- 6 files changed, 24 insertions(+), 16 deletions(-) delete mode 100644 src/PostIt/PostIt/Views/InitialPage.cs diff --git a/src/PostIt/PostIt/App.axaml.cs b/src/PostIt/PostIt/App.axaml.cs index ca7e051d..1e0afeaf 100644 --- a/src/PostIt/PostIt/App.axaml.cs +++ b/src/PostIt/PostIt/App.axaml.cs @@ -25,7 +25,7 @@ public partial class App : Application /// DataValidationErrors.SetErrors. /// public IServiceProvider? Services { get; private set; } - + private MainWindow window; public App() { } @@ -137,7 +137,7 @@ public partial class App : Application var homePage = provider.GetRequiredService(); homePage.DataContext = provider.GetRequiredService(); - var window = new MainWindow(); + window = new MainWindow(); window.SessionBanner.DataContext = sessionStatus; // Build the navigation stack from scratch: HomePage is the @@ -165,7 +165,7 @@ public partial class App : Application sessionStatus.LoginSucceeded += () => { var w = (MainWindow)((IClassicDesktopStyleApplicationLifetime)ApplicationLifetime!).MainWindow!; - _ = PushMainPageAsync(provider, w); + _ = PushMainPageAsync(); }; // When the user clicks the "Paramètres" button on the @@ -196,7 +196,7 @@ public partial class App : Application _ = w.NavRoot.PushAsync(settingsPage); }; - window.Opened += async (_, _) => await BootAsync(provider, api, window); + window.Opened += async (_, _) => await BootAsync(provider, api); } else if (ApplicationLifetime is ISingleViewApplicationLifetime singleView) { @@ -223,15 +223,14 @@ public partial class App : Application /// private static async Task BootAsync( IServiceProvider provider, - YavscApiClient api, - MainWindow window) + YavscApiClient api) { var refreshed = await api.TrySilentLoginAsync().ConfigureAwait(true); var sessionStatus = provider.GetRequiredService(); sessionStatus.Refresh(); if (!refreshed) return; - await PushMainPageAsync(provider, window).ConfigureAwait(true); + await PushMainPageAsync().ConfigureAwait(true); } /// @@ -241,12 +240,13 @@ public partial class App : Application /// (interactive login from the banner). Pulled out as a helper so /// the two callers can't drift apart. /// - private static async Task PushMainPageAsync(IServiceProvider provider, MainWindow window) + public static async Task PushMainPageAsync() { - var mainVm = provider.GetRequiredService(); - var mainPage = provider.GetRequiredService(); + var app = (App)Current; + var mainVm = app.Services.GetRequiredService(); + var mainPage = app.Services.GetRequiredService(); mainPage.DataContext = mainVm; - await window.NavRoot.PushAsync(mainPage).ConfigureAwait(true); + await app.window.FindControl("NavRoot").PushAsync(mainPage).ConfigureAwait(true); } private bool TryHandOffCustomSchemeUrl() diff --git a/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs b/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs index 8d5b3a17..c11e396a 100644 --- a/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/HomePageViewModel.cs @@ -1,6 +1,7 @@ +using CommunityToolkit.Mvvm.Input; using PostIt; using PostIt.Services; -using PostIt.ViewModels; +namespace PostIt.ViewModels; public class HomePageViewModel : ViewModelBase { @@ -22,7 +23,7 @@ public class HomePageViewModel : ViewModelBase Api = api; Settings = settings; } - + public RelayCommand OpenBlogs { get; set; } = new RelayCommand(() => App.PushMainPageAsync()); /// /// Avalonia designer constructor. Builds a self-contained VM /// with a freshly-constructed Settings so the XAML preview can diff --git a/src/PostIt/PostIt/Views/HomePage.axaml b/src/PostIt/PostIt/Views/HomePage.axaml index 82473542..7eb6dbb3 100644 --- a/src/PostIt/PostIt/Views/HomePage.axaml +++ b/src/PostIt/PostIt/Views/HomePage.axaml @@ -1,7 +1,12 @@ + + + @@ -9,5 +14,8 @@ FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/> +