summaryrefslogtreecommitdiffstats
path: root/src/Utilities
diff options
context:
space:
mode:
authorivar <i@oiee.no>2025-10-19 23:41:23 +0200
committerivar <i@oiee.no>2025-10-19 23:41:23 +0200
commit3f4c0720e1e3421431e7baa20882a4a4512a7fab (patch)
tree734ca81d7d0841d8863e3f523ebba14c282dc681 /src/Utilities
downloadfagprove-3f4c0720e1e3421431e7baa20882a4a4512a7fab.tar.xz
fagprove-3f4c0720e1e3421431e7baa20882a4a4512a7fab.zip
InitialHEADmaster
Diffstat (limited to 'src/Utilities')
-rw-r--r--src/Utilities/ClaimExtensions.cs16
-rw-r--r--src/Utilities/Config.cs28
-rw-r--r--src/Utilities/Cryptography.cs26
-rw-r--r--src/Utilities/Email.cs56
-rw-r--r--src/Utilities/Helpers.cs19
-rw-r--r--src/Utilities/PasswordHasher.cs18
-rw-r--r--src/Utilities/ServicesCollectionExtensions.cs62
-rw-r--r--src/Utilities/Validators.cs50
8 files changed, 275 insertions, 0 deletions
diff --git a/src/Utilities/ClaimExtensions.cs b/src/Utilities/ClaimExtensions.cs
new file mode 100644
index 0000000..f8becc2
--- /dev/null
+++ b/src/Utilities/ClaimExtensions.cs
@@ -0,0 +1,16 @@
+using System.Linq;
+using System.Security.Claims;
+using System.Security.Principal;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class ClaimExtensions
+ {
+ public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
+ {
+ var identity = currentPrincipal.Identity as ClaimsIdentity;
+ var claim = identity?.Claims.FirstOrDefault(c => c.Type == key);
+ return claim?.Value;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/Config.cs b/src/Utilities/Config.cs
new file mode 100644
index 0000000..79f7b58
--- /dev/null
+++ b/src/Utilities/Config.cs
@@ -0,0 +1,28 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.CookiePolicy;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class Config
+ {
+ public static string GetConnectionString(this IConfiguration config)
+ {
+ var databaseName = config.GetValue<string>("MYSQL_DB", "fagprove");
+ var port = config.GetValue<string>("MYSQL_PORT", "3306");
+ var host = config.GetValue<string>("MYSQL_HOST", "localhost");
+ var user = config.GetValue<string>("MYSQL_USER", "root");
+ var password = config.GetValue<string>("MYSQL_PASSWORD", "okpassword10");
+ var res = $"server={host};port={port};user={user};password={password};database={databaseName}";
+ return res;
+ }
+
+ public static CookiePolicyOptions CookiePolicyOptions => new CookiePolicyOptions
+ {
+ MinimumSameSitePolicy = SameSiteMode.Lax,
+ HttpOnly = HttpOnlyPolicy.Always,
+ Secure = CookieSecurePolicy.SameAsRequest
+ };
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/Cryptography.cs b/src/Utilities/Cryptography.cs
new file mode 100644
index 0000000..cdf4984
--- /dev/null
+++ b/src/Utilities/Cryptography.cs
@@ -0,0 +1,26 @@
+using System.Security.Cryptography;
+using System.Text;
+
+namespace IOL.Fagprove.Utilities
+{
+ public class Cryptography
+ {
+ public static string RandomString(int length = 12)
+ {
+ var chars = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
+ var data = new byte[length];
+ using (var crypto = new RNGCryptoServiceProvider())
+ {
+ crypto.GetBytes(data);
+ }
+
+ var result = new StringBuilder(length);
+ foreach (var b in data)
+ {
+ result.Append(chars[b % (chars.Length)]);
+ }
+
+ return result.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/Email.cs b/src/Utilities/Email.cs
new file mode 100644
index 0000000..248db32
--- /dev/null
+++ b/src/Utilities/Email.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Net.Mail;
+using System.Net;
+
+namespace IOL.Fagprove.Utilities
+{
+ public class Email
+ {
+ public string Recepient { get; set; }
+ public string Message { get; set; }
+ public string Title { get; set; }
+ public bool Valid { get; private set; }
+ public bool Sent { get; private set; }
+
+ public bool Send()
+ {
+ if (!Validate()) return false;
+ var client = new SmtpClient("smtp.server.com", 587)
+ {
+ EnableSsl = true,
+ Credentials = new NetworkCredential("user", "pass")
+ };
+ var from = new MailAddress("bot@bottesen.no", "Hal", System.Text.Encoding.UTF8);
+ var to = new MailAddress(Recepient);
+ var message = new MailMessage(from, to)
+ {
+ Body = Message,
+ BodyEncoding = System.Text.Encoding.UTF8,
+ Subject = Title,
+ SubjectEncoding = System.Text.Encoding.UTF8
+ };
+#if DEBUG
+ Console.WriteLine(Message);
+#else
+ client.Send(message);
+#endif
+ Sent = true;
+ return true;
+ }
+
+ private bool Validate()
+ {
+ if (Recepient.IsMissing()
+ || Title.IsMissing()
+ || Message.IsMissing()
+ || !Recepient.IsEmail())
+ {
+ Valid = false;
+ return false;
+ }
+
+ Valid = true;
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/Helpers.cs b/src/Utilities/Helpers.cs
new file mode 100644
index 0000000..ba9b648
--- /dev/null
+++ b/src/Utilities/Helpers.cs
@@ -0,0 +1,19 @@
+using System;
+using IOL.Fagprove.Data.Enums;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class Helpers
+ {
+ public static Guid ToGuid(this string input)
+ {
+ return input.IsGuid() ? new Guid(input) : default;
+ }
+
+ public static UserRole ToUserRole(this string input)
+ {
+ var isEnum = Enum.TryParse(input, out UserRole role);
+ return isEnum ? role : default;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/PasswordHasher.cs b/src/Utilities/PasswordHasher.cs
new file mode 100644
index 0000000..213e03d
--- /dev/null
+++ b/src/Utilities/PasswordHasher.cs
@@ -0,0 +1,18 @@
+using IOL.Fagprove.Data.Models;
+using Microsoft.AspNetCore.Identity;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class PasswordHasher
+ {
+ public static string HashPassword(string password) {
+ var hasher = new PasswordHasher<User>();
+ return hasher.HashPassword(null, password);
+ }
+
+ public static bool PasswordMatches(string hash, string password) {
+ var hasher = new PasswordHasher<User>();
+ return hasher.VerifyHashedPassword(null, hash, password) == PasswordVerificationResult.Success;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/ServicesCollectionExtensions.cs b/src/Utilities/ServicesCollectionExtensions.cs
new file mode 100644
index 0000000..0e3b05e
--- /dev/null
+++ b/src/Utilities/ServicesCollectionExtensions.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Security.Claims;
+using IOL.Fagprove.Data;
+using IOL.Fagprove.Data.Enums;
+using IOL.Fagprove.Services;
+using IOL.Fagprove.Services.Interfaces;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using StackExchange.Redis;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class ServicesCollectionExtensions
+ {
+ public static void AddServices(this IServiceCollection services)
+ {
+ services.AddScoped<IUserService, UserService>();
+ services.AddScoped<IAppReservationService, AppReservationService>();
+ }
+
+ public static void AddAppDbContext(this IServiceCollection services, IConfiguration config)
+ {
+ services.AddDbContext<AppDbContext>(options =>
+ {
+ options.UseMySql(config.GetConnectionString(),
+ builder => builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(60), null));
+#if DEBUG
+ options.EnableSensitiveDataLogging();
+#endif
+ });
+ }
+
+ public static void AddDataProtectionWithRedis(this IServiceCollection services, IConfiguration config)
+ {
+ var accessKey = config.GetValue<string>("REDIS_KEY");
+ if (!accessKey.IsPresent()) return;
+ var redis = ConnectionMultiplexer.Connect(
+ $"aredis.cache.net:6380,password={accessKey},ssl=True,abortConnect=False");
+ services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, "IOL.Fagprove.DataProtectionKeys");
+ }
+
+ public static void AddInternalUserPolicies(this IServiceCollection services)
+ {
+ services.Configure<AuthorizationOptions>(options =>
+ {
+ options.AddPolicy(UserRole.Administrator.ToString(), policy =>
+ {
+ policy.RequireAuthenticatedUser();
+ policy.RequireClaim(ClaimTypes.Role, UserRole.Administrator.ToString());
+ });
+ options.AddPolicy(UserRole.Basic.ToString(), policy =>
+ {
+ policy.RequireAuthenticatedUser();
+ policy.RequireClaim(ClaimTypes.Role, new string[] {UserRole.Basic.ToString()});
+ });
+ });
+ }
+ }
+} \ No newline at end of file
diff --git a/src/Utilities/Validators.cs b/src/Utilities/Validators.cs
new file mode 100644
index 0000000..e49d49a
--- /dev/null
+++ b/src/Utilities/Validators.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace IOL.Fagprove.Utilities
+{
+ public static class Validators
+ {
+ public static bool IsEmail(this string email)
+ {
+ try
+ {
+ const string pattern =
+ @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$";
+ var regex = new Regex(pattern);
+ var match = regex.Match(email);
+ return match.Success;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public static bool IsMissing(this string value)
+ {
+ return string.IsNullOrWhiteSpace(value);
+ }
+
+ public static bool IsPresent(this string value)
+ {
+ return !value.IsMissing();
+ }
+
+ public static bool IsNumeric(this string value)
+ {
+ var r = new Regex(@"[0-9]");
+ return r.IsMatch(value);
+ }
+
+ public static bool IsInt(this string value)
+ {
+ return int.TryParse(value, out _);
+ }
+
+ public static bool IsGuid(this string value)
+ {
+ return Guid.TryParse(value, out _);
+ }
+ }
+} \ No newline at end of file