Skip to content

Commit

Permalink
improved my api backend for LCP (pt 2)
Browse files Browse the repository at this point in the history
  • Loading branch information
carvalholuigi25 committed Nov 22, 2023
1 parent fe3aae5 commit 50d93c5
Show file tree
Hide file tree
Showing 30 changed files with 1,588 additions and 67 deletions.
2 changes: 1 addition & 1 deletion backend/api/LCPApi/Context/DBContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ protected override void OnModelCreating(ModelBuilder mb)
{
base.OnModelCreating(mb);
new DBOpData(mb).SetupForeignKeys(false);
new DBOpData(mb).Seed(false);
new DBOpData(mb).Seed(true);
}
}
2 changes: 1 addition & 1 deletion backend/api/LCPApi/Context/DBOpData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void Seed(Boolean isSeedData)
int seedval = 1000;

List<Employee> listEmp = [
new Employee { EmployeeId = 1001, EmployeeFirstName = "Luis", EmployeeLastName = "Carvalho", EmployeeCity = "Braga", EmployeeCountry = "Portugal", EmployeeStateProvince = "", EmployeeName = "luigicardev96", EmployeeEmail = "[email protected]", EmployeeDateBirthday = DateTime.Parse("1996-06-04T00:00:00"), EmployeeDateRegistered = DateTime.Now, EmployeePassword = BC.HashPassword("luigi1234"), EmployeePin = 1234, EmployeeJob = "Programmer", EmployeePhoneNumber = "0123456789", EmployeePostalAddress = "1234-567", EmployeeZipCode = "1234-567", EmployeeRole = ENRoles.Administrator.ToString(), Products = null }
new Employee { EmployeeId = 1001, EmployeeFirstName = "Luis", EmployeeLastName = "Carvalho", EmployeeCity = "Braga", EmployeeCountry = "Portugal", EmployeeStateProvince = "", EmployeeName = "admin", EmployeeEmail = "[email protected]", EmployeeDateBirthday = DateTime.Parse("1996-06-04T00:00:00"), EmployeeDateRegistered = DateTime.Now, EmployeePassword = BC.HashPassword("Kw@?7t3z704M6-6B92XG"), EmployeePin = BC.HashPassword("1234"), EmployeeJob = "Programmer", EmployeePhoneNumber = "0123456789", EmployeePostalAddress = "1234-567", EmployeeZipCode = "1234-567", EmployeeRole = ENRoles.Administrator.ToString(), Products = null }
];

_mb.Entity<Employee>(b => {
Expand Down
45 changes: 45 additions & 0 deletions backend/api/LCPApi/Controllers/AuthController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using BC = BCrypt.Net.BCrypt;
using Microsoft.AspNetCore.Authorization;
using LCPApi.Functions;
using LCPApi.Context;
using Microsoft.EntityFrameworkCore;

namespace LCPApi.Controllers
{
[Route("api/auth/login")]
[ApiController]
[AllowAnonymous]
public class AuthController : ControllerBase
{
private readonly IConfiguration _config;
private readonly DBContext _dbc;
public AuthController(IConfiguration config, DBContext dbc)
{
_config = config;
_dbc = dbc;
}

/// <summary>
/// Login authentication for LCP Api
/// </summary>
/// <param name="userauth"></param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> DoAuth(UserAuth userauth)
{
var users = await _dbc.Employees.SingleOrDefaultAsync(x => x.EmployeeName == userauth.UserAuthName);

if(users == null || !CheckIfPassOrPinIsValid(userauth.UserAuthPassword, users.EmployeePassword)) {
return Problem($"The authentication of this user {userauth.UserAuthName} is invalid!");
}

return Ok(AuthFunctions.GenToken(_config, userauth));
}

private bool CheckIfPassOrPinIsValid(string originalPass, string hashedPass) {
return BC.Verify(originalPass, hashedPass, false, BCrypt.Net.HashType.SHA512);
}
}
}
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/CategoryController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "StaffOnly")]
public class CategoryController : ControllerBase
{
private readonly ICategory _categoryRepo;
Expand Down
3 changes: 2 additions & 1 deletion backend/api/LCPApi/Controllers/CustomerController.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Repositories;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "StaffOnly")]
public class CustomerController : ControllerBase
{
private readonly ICustomer _customerRepo;
Expand Down
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/DepartmentController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "StaffOnly")]
public class DepartmentController : ControllerBase
{
private readonly IDepartment _departmentRepo;
Expand Down
4 changes: 2 additions & 2 deletions backend/api/LCPApi/Controllers/EmployeeController.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
// [Authorize(Policy = "AllRights")]
[Authorize(Policy = "StaffOnly")]
public class EmployeeController : ControllerBase
{
private readonly IEmployee _employeeRepo;
Expand Down
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/FeedbackController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class FeedbackController : ControllerBase
{
private readonly IFeedback _feedbackRepo;
Expand Down
2 changes: 0 additions & 2 deletions backend/api/LCPApi/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace LCPApi.Controllers;

// [ApiController]
// [NonController]
[ApiExplorerSettings(IgnoreApi = true)]
[Route("")]
[Route("[controller]")]
Expand Down
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/OrderController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class OrderController : ControllerBase
{
private readonly IOrder _orderRepo;
Expand Down
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/ProductController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class ProductController : ControllerBase
{
private readonly IProduct _productRepo;
Expand Down
2 changes: 2 additions & 0 deletions backend/api/LCPApi/Controllers/ProjectController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using Microsoft.AspNetCore.Authorization;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class ProjectController : ControllerBase
{
private readonly IProject _projectRepo;
Expand Down
9 changes: 9 additions & 0 deletions backend/api/LCPApi/Controllers/SubscriptionController.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using LCPApi.Models;
using LCPApi.Interfaces;
using LCPApi.Functions;

namespace LCPApi.Controllers
{
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "StaffOnly")]
public class SubscriptionController : ControllerBase
{
private readonly ISubscription _subscriptionRepo;
Expand Down Expand Up @@ -45,6 +48,12 @@ public async Task<IActionResult> DeleteSubscription(int id)
return await _subscriptionRepo.DeleteSubscription(id);
}

[HttpGet("genpkey")]
public async Task<ActionResult<IEnumerable<ProductKeyClass>>> GenerateProdKey()
{
return await ProductKeyFunctions.GetProductKey();
}

[HttpGet("key")]
public async Task<ActionResult<IEnumerable<SubscriptionKey>>> GetSubscriptionKey()
{
Expand Down
16 changes: 8 additions & 8 deletions backend/api/LCPApi/Functions/AuthFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
namespace LCPApi.Functions;
public static class AuthFunctions
{
public static IResult GenToken(WebApplicationBuilder builder, UserAuth userauth)
public static string GenToken(IConfiguration config, UserAuth userauth)
{
if (userauth.UserAuthName == builder.Configuration["userAuth:username"] && userauth.UserAuthPassword == builder.Configuration["userAuth:userpass"])
if (userauth.UserAuthName == config["userAuth:username"] && userauth.UserAuthPassword == config["userAuth:userpass"])
{
var issuer = builder.Configuration["Jwt:Issuer"];
var audience = builder.Configuration["Jwt:Audience"];
var key = Encoding.ASCII.GetBytes(builder.Configuration["Jwt:Key"]!);
var issuer = config["Jwt:Issuer"];
var audience = config["Jwt:Audience"];
var key = Encoding.ASCII.GetBytes(config["Jwt:Key"]!);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", Guid.NewGuid().ToString()),
new Claim("Role", ENRoles.Administrator.ToString()),
new Claim(ClaimTypes.Role, ENRoles.Administrator.ToString()),
new Claim(JwtRegisteredClaimNames.Name, ""+userauth.UserAuthName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
Expand All @@ -32,8 +32,8 @@ public static IResult GenToken(WebApplicationBuilder builder, UserAuth userauth)
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var stringToken = tokenHandler.WriteToken(token);
return Results.Ok(stringToken);
return stringToken;
}
return Results.Unauthorized();
return "Unauthorized";
}
}
128 changes: 128 additions & 0 deletions backend/api/LCPApi/Functions/ProductKeyFunctions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System.Text;
using System.Security.Cryptography;

namespace LCPApi.Functions;

public class ProductKeyClass {
public Guid? Id { get; set; } = Guid.NewGuid();
public string? SecretKey { get; set; }
public string? PrivateKey { get; set; }
public string? LicenseKey { get; set; }
public string? Msg { get; set; }
public bool? IsValid { get; set; }
public DateTime? DateExp { get; set; }
public DateTime? DateNow { get; set; }
}

public static class ProductKeyFunctions
{
public async static Task<List<ProductKeyClass>> GetProductKey() {
//src: https://dotnetfiddle.net/srGTKN
//var secretKey = CreatePrivateKey();
var secretKey = "+bCzRidhVxwx5TKpkz14nf5cL+BMH+ahZIOCy4bPVzdXWhysq+tZfOtrHsw9vdg5vKes/lVwzHIyquvmz9taDg==";
var privateKey = CreatePrivateKey();
var licenseKey = CreateLicense(secretKey);
var isValid = ValidateLicense(licenseKey, secretKey);
var validStatus = isValid ? "valid" : "invalid";
Random rnd = new Random();

return await Task.FromResult(new List<ProductKeyClass>() {
new ProductKeyClass() {
Id = Guid.NewGuid(),
SecretKey = secretKey,
PrivateKey = privateKey,
LicenseKey = licenseKey,
Msg = $"This product license key is {validStatus}",
IsValid = isValid,
DateExp = DateTime.UtcNow.AddMonths(rnd.Next(1, 13)),
DateNow = DateTime.UtcNow
}
});
}

static string CreatePrivateKey()
{
// Step 01: Create your private hashkey and store it on the database
byte[] hashKey = GenerateRandomCryptographicBytes(64);

// Convert the key to base64 so you can easily store it on the database.
// This should be kept private and never leaves your control.
var base64Secret = Convert.ToBase64String(hashKey);

Console.WriteLine($"Private Key = {base64Secret}");

return base64Secret;
}

static string CreateLicense(string secretKey)
{
// Generate a license key of 10 chars (split into groups of 5)
var licenseKey = Guid.NewGuid().ToString().ToUpper().Replace("-", "").Substring(0, 15);

Console.WriteLine($"licenseKey = {licenseKey}");

// Generate a Hmac license using secretkey
var storedHmacOnDB = CalculateHmac(licenseKey, secretKey).ToUpper();
var HMACTruncated = storedHmacOnDB.Substring(0, 15);

Console.WriteLine($"HMAC = {HMACTruncated}");

var licenseAndHMAC = InsertHyphen($"{licenseKey}{HMACTruncated}");

Console.WriteLine($"Final User License = {licenseAndHMAC}");

return licenseAndHMAC;
}

static bool ValidateLicense(string licenseKey, string secretKey)
{
var tmp = licenseKey.Split('-');

var license = $"{tmp[0]}{tmp[1]}{tmp[2]}";
var licenseHmac = $"{tmp[3]}{tmp[4]}{tmp[5]}";

string calculatedHmac = CalculateHmac(license, secretKey);
var HMACTruncated = calculatedHmac.ToUpper().Substring(0, 15);

bool isValid = licenseHmac.Equals(HMACTruncated, StringComparison.OrdinalIgnoreCase);

return isValid;
}

static string InsertHyphen(string input, int everyNthChar = 5)
{
var sb = new StringBuilder();
for (int i = 0; i < input.Length; i++)
{
sb.Append(input[i]);
if ((i + 1) % everyNthChar == 0 && i != input.Length - 1)
{
sb.Append("-");
}
}
return sb.ToString();
}

static byte[] GenerateRandomCryptographicBytes(int keyLength)
{
byte[] key = new byte[64];
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
rng.GetBytes(key);
}
return key;
}

static string CalculateHmac(string data, string hashKeyBase64)
{
var byteArray = Convert.FromBase64String(hashKeyBase64);
return CalculateHmac(data, byteArray);
}

static string CalculateHmac(string data, byte[] hashKey)
{
var hmac = new HMACMD5(hashKey);
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
9 changes: 9 additions & 0 deletions backend/api/LCPApi/Hubs/DataHub.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.AspNetCore.SignalR;

namespace LCPApi.Hubs;

public class DataHub : Hub {
public async Task SendData(string user, string data) {
await Clients.All.SendAsync("ReceiveData", user, data);
}
}
Loading

0 comments on commit 50d93c5

Please sign in to comment.