summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-09-13 16:01:02 +1000
committerJake Mannens <jake@asger.xyz>2023-09-13 16:01:02 +1000
commite6e43b943143d55581ef442b61ed6cbdbb40c642 (patch)
tree82dc5ba12d2761baf8b9290804d3481cdf4eb4cb
parentbd46d1ff8f2bbe43a92e935aafadc1a63b3a1a5b (diff)
Added logon page
-rw-r--r--MainLayout.razor22
-rw-r--r--MainLayout.razor.css53
-rw-r--r--Pages/Component/Titlebar.razor64
-rw-r--r--Pages/Component/Titlebar.razor.css79
-rw-r--r--Pages/Login.razor5
-rw-r--r--Pages/Login.razor.css6
-rw-r--r--Pages/ViewMedia.razor2
-rw-r--r--Program.cs4
-rw-r--r--Services/GlobalUserService.cs7
-rw-r--r--Services/UserService.cs42
-rw-r--r--wwwroot/images/loginbg.webpbin0 -> 2247672 bytes
-rw-r--r--wwwroot/js/keyboard.js4
12 files changed, 210 insertions, 78 deletions
diff --git a/MainLayout.razor b/MainLayout.razor
index 2d3cadc..5d68b65 100644
--- a/MainLayout.razor
+++ b/MainLayout.razor
@@ -2,28 +2,8 @@
<link href="@(nameof(HyperBooru)).styles.css" rel="stylesheet" />
-<div id="navbar">
- <a href="/">Home</a>
- <a href="/TagDefinitions">Tags</a>
- <a href="/Gallery?ingest=true">Ingest</a>
- <a href="/Upload">Upload</a>
- <a href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a>
-
- <p id="nsfw-label">NSFW</p>
- <div id="nsfw-switch">
- <NsfwSwitch/>
- </div>
- <form action="/Gallery" method="get">
- <input type="text" name="q" placeholder="Search"/>
- </form>
-</div>
+<Titlebar/>
<div id="content">
@Body
</div>
-
-<AboutDialog @ref=aboutDialog/>
-
-@code {
- private AboutDialog aboutDialog;
-}
diff --git a/MainLayout.razor.css b/MainLayout.razor.css
index b0dea4e..0ce15c2 100644
--- a/MainLayout.razor.css
+++ b/MainLayout.razor.css
@@ -1,55 +1,4 @@
-div#navbar {
- background: var(--col-navbar-bg);
- box-shadow: rgba(0, 0, 0, 0.5) 0px 10px 10px;
- display: flex;
- z-index: 100;
-}
-
-div#navbar > a {
- color: white;
- display: inline-block;
- padding: 20px 20px 20px 20px;
-}
-
-div#navbar > a:hover {
- background: rgba(255, 255, 255, 0.4);
- filter: none;
-}
-
-div#navbar > a:active {
- background: #fff;
- color: var(--col-navbar-bg);
-}
-
-p#nsfw-label {
- align-self: center;
- font-size: 9pt;
- margin-left: auto;
-}
-
-div#nsfw-switch {
- align-self: center;
- margin-left: 10px;
-}
-
-div#navbar form {
- display: flex;
- margin: 0 20px 0 20px;
- min-width: 30%;
-}
-
-div#navbar input[type="text"] {
- align-self: center;
- background: var(--col-bg);
- border-radius: 0;
- color: white;
- font-size: 12pt;
- height: 40px !important;
- margin: 0;
- width: 100%;
-}
-
-#content {
+#content {
flex: 1 1 calc(100vh - 59px);
overflow-x: hidden;
overflow-y: auto;
diff --git a/Pages/Component/Titlebar.razor b/Pages/Component/Titlebar.razor
new file mode 100644
index 0000000..71f3bd0
--- /dev/null
+++ b/Pages/Component/Titlebar.razor
@@ -0,0 +1,64 @@
+@inject IUserService userService
+@inject NavigationManager navigationManager
+@inject IJSRuntime jsRuntime
+
+@if(authorized) {
+ <div id="navbar">
+ <a href="/">Home</a>
+ <a href="/TagDefinitions">Tags</a>
+ <a href="/Gallery?ingest=true">Ingest</a>
+ <a href="/Upload">Upload</a>
+ <a href="javascript:;" @onclick=@(() => aboutDialog.Show())>About</a>
+
+ <p id="nsfw-label">NSFW</p>
+ <div id="nsfw-switch">
+ <NsfwSwitch/>
+ </div>
+ <form action="/Gallery" method="get">
+ <input type="text" name="q" placeholder="Search"/>
+ </form>
+ <a href="javascript:;" @onclick=userService.Logout>Logout</a>
+ </div>
+ <AboutDialog @ref=aboutDialog/>
+} else {
+ <div id="navbar">
+ <h2>Login</h2>
+ <form @onsubmit=Login class="login">
+ <input @bind=username name="username" placeholder="Username" type="text"/>
+ <input @bind=password name="password" placeholder="Password" type="password"/>
+ </form>
+ <a href="javascript:;" @onclick=Login>Login</a>
+ <a href="javascript:;" @onclick=userService.Logout>Logout</a>
+ </div>
+ <script suppress-error="BL9992">
+ function warnBadLogin() {
+ var form = document.querySelector('form.login');
+ form.classList.remove('bad-login');
+ @* TODO: improve this hacky method of triggering reflow *@
+ form.offsetWidth;
+ form.classList.add('bad-login');
+ document.querySelector('form.login input').focus();
+ }
+ </script>
+}
+
+@code {
+ private bool authorized = false;
+
+ private string username;
+ private string password;
+
+ private AboutDialog aboutDialog;
+
+ private void Login() {
+ if(userService.Login(username, password))
+ navigationManager.NavigateTo("/");
+ else
+ WarnBadLogin();
+ }
+
+ private void WarnBadLogin() {
+ jsRuntime.InvokeVoidAsync("warnBadLogin");
+ username = password = "";
+ }
+}
diff --git a/Pages/Component/Titlebar.razor.css b/Pages/Component/Titlebar.razor.css
new file mode 100644
index 0000000..ea10740
--- /dev/null
+++ b/Pages/Component/Titlebar.razor.css
@@ -0,0 +1,79 @@
+div#navbar {
+ align-items: center;
+ background: var(--col-navbar-bg);
+ box-shadow: rgba(0, 0, 0, 0.5) 0px 10px 10px;
+ display: flex;
+ height: 59px;
+ z-index: 100;
+}
+
+div#navbar > h2 {
+ margin-left: 20px;
+}
+
+div#navbar > a {
+ align-items: center;
+ color: white;
+ display: flex;
+ height: 100%;
+ padding: 0 20px 0 20px;
+}
+
+div#navbar > a:hover {
+ background: rgba(255, 255, 255, 0.4);
+ filter: none;
+}
+
+div#navbar > a:active {
+ background: #fff;
+ color: var(--col-navbar-bg);
+}
+
+p#nsfw-label {
+ align-self: center;
+ font-size: 9pt;
+ margin-left: auto;
+}
+
+div#nsfw-switch {
+ align-self: center;
+ margin-left: 10px;
+}
+
+form {
+ display: flex;
+ margin: 0 20px 0 20px;
+ min-width: 30%;
+}
+
+form.login {
+ margin-left: auto;
+}
+
+form.login.bad-login {
+ animation-iteration-count: 3;
+ animation-timing-function: linear;
+ animation: bad-login 0.2s;
+}
+
+@keyframes bad-login {
+ 0% { transform: translateX(0); }
+ 33% { transform: translateX(-20px); }
+ 66% { transform: translateX(+20px); }
+ 100% { transform: translateX(0); }
+}
+
+input[type="text"], input[type="password"] {
+ align-self: center;
+ background: var(--col-bg);
+ border-radius: 0;
+ color: white;
+ font-size: 12pt;
+ height: 40px !important;
+ margin: 0;
+ width: 100%;
+}
+
+input[type="password"] {
+ margin-left: 20px;
+}
diff --git a/Pages/Login.razor b/Pages/Login.razor
new file mode 100644
index 0000000..2970731
--- /dev/null
+++ b/Pages/Login.razor
@@ -0,0 +1,5 @@
+@page "/Login"
+
+<PageTitle>HyperBooru Login</PageTitle>
+
+<div/> \ No newline at end of file
diff --git a/Pages/Login.razor.css b/Pages/Login.razor.css
new file mode 100644
index 0000000..fc8c8ca
--- /dev/null
+++ b/Pages/Login.razor.css
@@ -0,0 +1,6 @@
+div {
+ background: url('/images/loginbg.webp');
+ filter: brightness(0.6);
+ height: 100%;
+ width: 100%;
+} \ No newline at end of file
diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor
index 444fbc5..1b6f959 100644
--- a/Pages/ViewMedia.razor
+++ b/Pages/ViewMedia.razor
@@ -4,7 +4,7 @@
@inject IDbContextFactory<HBContext> dbFactory
@inject ITagService tagService
@inject IMediaService mediaService
-@attribute [Authorize]
+@*@attribute [Authorize]*@
<PageTitle>@title</PageTitle>
diff --git a/Program.cs b/Program.cs
index 564ab30..01b7949 100644
--- a/Program.cs
+++ b/Program.cs
@@ -7,6 +7,7 @@ namespace HyperBooru;
public class Program {
public static void Main(string[] args) {
var builder = WebApplication.CreateBuilder(args);
+ builder.Services.AddHttpContextAccessor();
builder.Services.AddControllers().AddJsonOptions(o => {
var converter = new JsonStringEnumConverter();
o.JsonSerializerOptions.Converters.Add(converter);
@@ -20,7 +21,8 @@ public class Program {
builder.Services.AddScoped<ISearchService, SearchService>();
builder.Services.AddScoped<ITagService, TagService>();
builder.Services.AddScoped<IMediaService, MediaService>();
- builder.Services.AddSingleton<IUserService, UserService>();
+ builder.Services.AddSingleton<IGlobalUserService, GlobalUserService>();
+ builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddHostedService<OcrService>();
var app = builder.Build();
diff --git a/Services/GlobalUserService.cs b/Services/GlobalUserService.cs
new file mode 100644
index 0000000..adafce2
--- /dev/null
+++ b/Services/GlobalUserService.cs
@@ -0,0 +1,7 @@
+namespace HyperBooru.Services;
+
+public interface IGlobalUserService {
+}
+
+public class GlobalUserService : IGlobalUserService {
+}
diff --git a/Services/UserService.cs b/Services/UserService.cs
index d2abea3..db62553 100644
--- a/Services/UserService.cs
+++ b/Services/UserService.cs
@@ -1,9 +1,17 @@
-namespace HyperBooru.Services;
+using Microsoft.AspNetCore.Authentication;
+using System.Runtime.InteropServices;
+using System.Security.Claims;
+using System.Security.Principal;
+
+namespace HyperBooru.Services;
public interface IUserService {
public bool ShowNsfw { get; set; }
public event EventHandler<bool> ShowNsfwChanged;
+
+ public bool Login(string username, string password);
+ public void Logout();
}
public class UserService : IUserService {
@@ -18,4 +26,36 @@ public class UserService : IUserService {
public event EventHandler<bool> ShowNsfwChanged;
private bool showNsfw = false;
+
+ private IGlobalUserService globalUserService;
+ private IHttpContextAccessor httpContextAccessor;
+
+ public UserService(
+ IGlobalUserService globalUserService,
+ IHttpContextAccessor httpContextAccessor) {
+
+ this.globalUserService = globalUserService;
+ this.httpContextAccessor = httpContextAccessor;
+ }
+
+ public bool Login(string username, string password) {
+ var claims = new Claim[] {
+ };
+
+ var claimsIdentity = new ClaimsIdentity(claims);
+
+ var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
+
+ if(httpContextAccessor.HttpContext is null)
+ return false;
+
+ httpContextAccessor.HttpContext.SignInAsync(claimsPrincipal)
+ .GetAwaiter()
+ .GetResult();
+
+ return true;
+ }
+
+ public void Logout() {
+ }
}
diff --git a/wwwroot/images/loginbg.webp b/wwwroot/images/loginbg.webp
new file mode 100644
index 0000000..759e666
--- /dev/null
+++ b/wwwroot/images/loginbg.webp
Binary files differ
diff --git a/wwwroot/js/keyboard.js b/wwwroot/js/keyboard.js
index 4c8e722..8086418 100644
--- a/wwwroot/js/keyboard.js
+++ b/wwwroot/js/keyboard.js
@@ -1,7 +1,7 @@
async function keyDownHandler(e) {
function isDialogChild(e) {
- while (e = e.parentElement)
- if (e.tagName == 'DIV' && e.classList.contains('dialog'))
+ while(e = e.parentElement)
+ if(e.tagName == 'DIV' && e.classList.contains('dialog'))
return true;
return false;
}