feat: added docker stuff, started working on login system

This commit is contained in:
limited_dev 2023-02-01 21:49:02 +01:00
parent c2d40c172a
commit 7c0cef6f65
15 changed files with 216 additions and 143 deletions

25
.dockerignore Normal file
View file

@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

View file

@ -1,16 +1,18 @@
<Router AppAssembly="@typeof(App).Assembly"> <CascadingAuthenticationState>
<Found Context="routeData"> <Router AppAssembly="@typeof(App).Assembly">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/> <Found Context="routeData">
<FocusOnNavigate RouteData="@routeData" Selector="h1"/> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
</Found> <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
<NotFound> </Found>
<PageTitle>Not found</PageTitle> <NotFound>
<LayoutView Layout="@typeof(MainLayout)"> <PageTitle>Not found</PageTitle>
<h3>404</h3> <LayoutView Layout="@typeof(MainLayout)">
<div class="Error404"> <h3>404</h3>
<img src="img/static/err/1.jpeg" alt="noimageFound"/> <div class="Error404">
<p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p> <img src="img/static/err/1.jpeg" alt="noimageFound"/>
</div> <p role="alert">Sorry, nothing found. Please go back to the main page. Or watch the tree and find the hidden Cat..</p>
</LayoutView> </div>
</NotFound> </LayoutView>
</Router> </NotFound>
</Router>
</CascadingAuthenticationState>

View file

@ -0,0 +1,60 @@
using System.Security.Claims;
using ImageBoardServerApp.Data;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
namespace ImageBoardServerApp.Auth;
public class CustomAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly ProtectedSessionStorage _sessionStorage;
private ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity());
public CustomAuthenticationStateProvider(ProtectedSessionStorage sessionStorage)
{
_sessionStorage = sessionStorage;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
try
{
var userSessionStorageResult = await _sessionStorage.GetAsync<UserData>("UserSession");
var userSession = userSessionStorageResult.Success ? userSessionStorageResult.Value : null;
if (userSession == null)
return await Task.FromResult(new AuthenticationState(_anonymous));
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Email, userSession.Email),
new Claim(ClaimTypes.Role, userSession.Role)
}, "CustomAuth"));
return await Task.FromResult(new AuthenticationState(claimsPrincipal));
}
catch
{
return await Task.FromResult(new AuthenticationState(_anonymous));
}
}
public async Task UpdateAuthenticationStateAsync(UserData session)
{
ClaimsPrincipal claimsPrincipal;
if (session != null)
{
await _sessionStorage.SetAsync("UserSession", session);
claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>
{
new Claim(ClaimTypes.Email, session.Email),
new Claim(ClaimTypes.Email, session.Role)
}));
}
else
{
await _sessionStorage.DeleteAsync("UserSession");
claimsPrincipal = _anonymous;
}
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal)));
}
}

View file

@ -0,0 +1,7 @@
namespace ImageBoardServerApp.Auth;
public class UserSession
{
public string Email { get; set; }
public string Role { get; set; }
}

View file

@ -1,21 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ImageBoardServerApp.Data;
public class AccountData
{
[Required]
[DatabaseGenerated((DatabaseGeneratedOption.Identity))]
[Key]
public int AccountID { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
public int PermissionInteger { get; set; }
}

View file

@ -8,7 +8,6 @@ internal sealed class AppDBContext : DbContext
public DbSet<PostData> Posts { get; set; } public DbSet<PostData> Posts { get; set; }
public DbSet<ImageData> Images { get; set; } public DbSet<ImageData> Images { get; set; }
public DbSet<CommentData> Comments { get; set; } public DbSet<CommentData> Comments { get; set; }
public DbSet<AccountData> Accounts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlite("Data Source=./Data/Nils.db"); => optionsBuilder.UseSqlite("Data Source=./Data/Nils.db");

View file

@ -1,53 +0,0 @@
using Microsoft.EntityFrameworkCore;
namespace ImageBoardServerApp.Data.Repository;
public static class AccountsRepository
{
public static async Task<List<AccountData>> getAccountsAsync()
{
await using var db = new AppDBContext();
return await db.Accounts.ToListAsync();
}
public static async Task<List<AccountData>> getAccountsByMailAsync(string email)
{
await using var db = new AppDBContext();
return await db.Accounts
.Where(acc => acc.Email.Equals(email))
.ToListAsync();
}
public static async Task<AccountData> getAccountByIdAsync(int accountId)
{
await using var db = new AppDBContext();
return await db.Accounts.FirstOrDefaultAsync(post => post.AccountID == accountId);
}
public static async Task<int> createAccountAsync(AccountData accountToCreate)
{
await using var db = new AppDBContext();
await db.Accounts.AddAsync(accountToCreate);
if (await db.SaveChangesAsync() >= 1)
{
Console.WriteLine($"Created post with ID: {accountToCreate.AccountID}");
return accountToCreate.AccountID;
}
return -1;
}
public static async Task<bool> updateAccountAsync(AccountData accountToUpdate)
{
await using var db = new AppDBContext();
db.Accounts.Update(accountToUpdate);
return await db.SaveChangesAsync() >= 1;
}
public static async Task<bool> deleteAccountAsync(int postId)
{
await using var db = new AppDBContext();
AccountData accountToDelete = await getAccountByIdAsync(postId);
db.Remove(accountToDelete);
return await db.SaveChangesAsync() >= 1;
}
}

View file

@ -16,10 +16,10 @@ public static class UsersRepository
return await db.Users.FirstOrDefaultAsync(user => user.UserID == userId); return await db.Users.FirstOrDefaultAsync(user => user.UserID == userId);
} }
public static async Task<UserData> getUserByIPAsync(string userIp) public static async Task<UserData> getUserByEmailAsync(string email)
{ {
await using var db = new AppDBContext(); await using var db = new AppDBContext();
return await db.Users.FirstOrDefaultAsync(user => user.Ipv4Address == userIp); return await db.Users.FirstOrDefaultAsync(user => user.Email == email);
} }
public static async Task<int> createUserAsync(UserData userToCreate) public static async Task<int> createUserAsync(UserData userToCreate)

View file

@ -13,10 +13,7 @@ public class UserData
public int UserID { get; set; } public int UserID { get; set; }
[Required] [Required]
public string Ipv4Address { get; set; } public long TimeBanned { get; set; }
[Required]
public bool Banned { get; set; }
[Required] [Required]
public long lastActionTimeStamp { get; set; } public long lastActionTimeStamp { get; set; }
@ -24,4 +21,16 @@ public class UserData
public List<PostData> Posts { get; set; } public List<PostData> Posts { get; set; }
public List<CommentData> Comments { get; set; } public List<CommentData> Comments { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
public int PermissionInteger { get; set; }
[Required]
public string Role { get; set; }
} }

View file

@ -0,0 +1,20 @@
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["ImageBoardServerApp/ImageBoardServerApp.csproj", "ImageBoardServerApp/"]
RUN dotnet restore "ImageBoardServerApp/ImageBoardServerApp.csproj"
COPY . .
WORKDIR "/src/BlazorServerTest"
RUN dotnet build "BlazorServerTest.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "ImageBoardServerApp.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ImageBoardServerApp.dll"]

View file

@ -1,6 +1,12 @@
@page "/Login" @page "/login"
@using ImageBoardServerApp.Data.Repository @using ImageBoardServerApp.Data.Repository
<h3>Login</h3> @using ImageBoardServerApp.Auth
@using System.Runtime.InteropServices
@inject IJSRuntime js
@inject AuthenticationStateProvider authStateProvider
@inject NavigationManager navManager
<h3>Login to bulletbroards</h3>
<div> <div>
<form> <form>
<div> <div>
@ -11,48 +17,41 @@
<label for="password">Password:</label> <label for="password">Password:</label>
<input type="password" id="password" @bind="Password" /> <input type="password" id="password" @bind="Password" />
</div> </div>
<button type="submit" @onclick="SubmitForm">Submit</button> <button type="submit" href="javascript:void(0)" @onclick="login">Submit</button>
</form> </form>
@if (tried)
{
@if (verified)
{
<span>Verifed!</span>
}
else
{
<span>False login</span>
}
}
else
{
<span>Plz login</span>
}
</div> </div>
@code { @code {
private string Email { get; set; } private string Email { get; set; }
private string Password { get; set; } private string Password { get; set; }
private bool verified = false; private bool verified;
private bool tried = false;
private async Task SubmitForm() private async Task login()
{ {
tried = true; Console.WriteLine("loggin you in...");
AccountData target = (await AccountsRepository.getAccountsByMailAsync(Email))[0]; var user = await UsersRepository.getUserByEmailAsync(Email);
if (target == null) if (user == null)
{ {
await js.InvokeVoidAsync("alert", "User does not exist");
verified = false; verified = false;
return; return;
} }
verified = BCrypt.Net.BCrypt.Verify(Password, target.Password); verified = BCrypt.Net.BCrypt.Verify(Password, user.Password);
if (verified) if (verified)
{ {
verified = true; verified = true;
var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvider;
await customAuthStateProvider.UpdateAuthenticationStateAsync(user);
navManager.NavigateTo("/", true);
return; return;
} }
verified = false; await js.InvokeVoidAsync("alert", $"Wrong creds:\n{BCrypt.Net.BCrypt.HashPassword(Password)}");
} }
/*
*
UserData target = (await UsersRepository.getUserByEmailAsync(Email));
*/
} }

View file

@ -1,14 +1,15 @@
using ImageBoardServerApp.Data; using ImageBoardServerApp.Auth;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Add services to the container. // Add services to the container.
builder.Services.AddAuthenticationCore();
builder.Services.AddRazorPages(); builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor(); builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<ProtectedSessionStorage>();
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
var app = builder.Build(); var app = builder.Build();

View file

@ -87,13 +87,15 @@
{ {
var userToCreate = new UserData var userToCreate = new UserData
{ {
Ipv4Address = "192.168.178.101", Email = "dev@limited-dev.de",
Banned = false, Password = "$2a$10$C/ZPY5aVGkImLGyIP0SySuQaEYIwnY0J99i/m6tqqf6tMkax89Eku",
PermissionInteger = 100,
TimeBanned = -1,
lastActionTimeStamp = DateTime.Now.Millisecond lastActionTimeStamp = DateTime.Now.Millisecond
}; };
int userID; int userID;
UserData foundusr = await UsersRepository.getUserByIPAsync(userToCreate.Ipv4Address); UserData foundusr = await UsersRepository.getUserByEmailAsync(userToCreate.Email);
if (foundusr == null) if (foundusr == null)
{ {
userID = await UsersRepository.createUserAsync(userToCreate); userID = await UsersRepository.createUserAsync(userToCreate);
@ -101,9 +103,9 @@
else else
{ {
userID = foundusr.UserID; userID = foundusr.UserID;
if(foundusr.Banned) if(foundusr.TimeBanned != -1)
return; return;
foundusr.lastActionTimeStamp = DateTime.Now.Millisecond; foundusr.lastActionTimeStamp = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
await UsersRepository.updateUserAsync(foundusr); await UsersRepository.updateUserAsync(foundusr);
} }

View file

@ -100,13 +100,15 @@
{ {
var userToCreate = new UserData var userToCreate = new UserData
{ {
Ipv4Address = "192.168.178.101", Email = "test@mail.org",
Banned = false, Password = "$2a$10$C/ZPY5aVGkImLGyIP0SySuQaEYIwnY0J99i/m6tqqf6tMkax89Eku",
PermissionInteger = 100,
TimeBanned = -1,
lastActionTimeStamp = DateTime.Now.Millisecond lastActionTimeStamp = DateTime.Now.Millisecond
}; };
int userID; int userID;
UserData foundusr = await UsersRepository.getUserByIPAsync(userToCreate.Ipv4Address); UserData foundusr = await UsersRepository.getUserByEmailAsync(userToCreate.Email);
if (foundusr == null) if (foundusr == null)
{ {
userID = await UsersRepository.createUserAsync(userToCreate); userID = await UsersRepository.createUserAsync(userToCreate);
@ -114,9 +116,9 @@
else else
{ {
userID = foundusr.UserID; userID = foundusr.UserID;
if(foundusr.Banned) if(foundusr.TimeBanned != -1)
return; return;
foundusr.lastActionTimeStamp = DateTime.Now.Millisecond; foundusr.lastActionTimeStamp = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
await UsersRepository.updateUserAsync(foundusr); await UsersRepository.updateUserAsync(foundusr);
} }

View file

@ -1,4 +1,7 @@
@inherits LayoutComponentBase @inherits LayoutComponentBase
@using ImageBoardServerApp.Auth
@inject AuthenticationStateProvider authStateProvder
@inject NavigationManager navManager
<PageTitle>BulletBoard</PageTitle> <PageTitle>BulletBoard</PageTitle>
@ -11,6 +14,14 @@
<div class="top-row px-4"> <div class="top-row px-4">
<a href="/faq">[FAQ]</a> <a href="/faq">[FAQ]</a>
<a href="/rules">[Rules]</a> <a href="/rules">[Rules]</a>
<AuthorizeView>
<Authorized>
<a @onclick="logout" href="javascript:void(0)">[Logout]</a>
</Authorized>
<NotAuthorized>
<a href="/login">[Login]</a>
</NotAuthorized>
</AuthorizeView>
</div> </div>
<article class="content px-4"> <article class="content px-4">
@ -18,3 +29,13 @@
</article> </article>
</main> </main>
</div> </div>
@code
{
private async Task logout()
{
var customAuthStateProvider = (CustomAuthenticationStateProvider)authStateProvder;
await customAuthStateProvider.UpdateAuthenticationStateAsync(null);
navManager.NavigateTo("/", true);
}
}