Files
timelog/backendCs/routes/Login.cs
T
2024-12-04 15:46:10 +02:00

134 lines
4.6 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Net;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Server
{
public class Login : Route
{
private static string secretKey =
"stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";
public static string GenerateToken(string user)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "TimeLogServer",
audience: "TimeLogWebsite",
claims: new[] { new Claim("user", user) },
expires: DateTime.Now.AddHours(2),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public static bool VerifyPassword(string enteredPassword, string storedHash)
{
byte[] hashBytes = Convert.FromBase64String(storedHash);
// Extract the salt from the stored hash
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
// Hash the entered password with the stored salt
using (
var pbkdf2 = new Rfc2898DeriveBytes(
enteredPassword,
salt,
10000,
HashAlgorithmName.SHA256
)
)
{
byte[] newHash = pbkdf2.GetBytes(32);
// Compare the computed hash with the stored hash
for (int i = 0; i < 32; i++)
{
if (newHash[i] != hashBytes[i + 16])
return false;
}
return true;
}
}
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
{
try
{
// extract data from body
string body;
using (
StreamReader bodyReader = new StreamReader(
request.InputStream,
request.ContentEncoding
)
)
{
body = bodyReader.ReadToEnd();
}
JObject jsonObject = JObject.Parse(body);
string mail = jsonObject["mail"]?.ToString() ?? "";
string password = jsonObject["password"]?.ToString() ?? "";
// prepare SQL query
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText =
@"SELECT u.id, password FROM User u
INNER JOIN Password p ON p.user=u.id
WHERE mail=@mail;";
cmd.Parameters.AddWithValue("@mail", mail);
using (MySqlConnection conn = new MySqlConnection(connectionString))
{
cmd.Connection = conn;
conn.Open();
// execute query and read results
MySqlDataReader reader = cmd.ExecuteReader();
string? userId = "";
string? hashedPass = "";
string? jsonResponse;
while (reader.Read())
{
userId = Convert.ToString(reader["id"]);
hashedPass = reader.GetString("password");
}
// check username
if (string.IsNullOrEmpty(userId))
{
throw new Exception("Invalid Username or Password");
}
//check password
if (
string.IsNullOrEmpty(password)
|| string.IsNullOrEmpty(hashedPass)
|| !VerifyPassword(password, hashedPass)
)
{
throw new Exception("Invalid Username or Password");
}
jsonResponse = JsonConvert.SerializeObject(GenerateToken(userId));
// prepare response
SendSuccess(response, jsonResponse);
}
}
catch (Exception ex)
{
SendError(response, ex);
}
}
}
}