added tests for backend, router dom to frontend
This commit is contained in:
@@ -1,99 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class CreateLog
|
||||
{
|
||||
private static string secretKey = "stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";
|
||||
public static bool ValidateToken(string token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var validationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidIssuer = "TimeLogServer",
|
||||
ValidAudience = "TimeLogWebsite",
|
||||
IssuerSigningKey = key
|
||||
};
|
||||
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
|
||||
return validatedToken != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
var headers = request.Headers;
|
||||
string? token = headers["token"];
|
||||
if (!ValidateToken(token))
|
||||
{
|
||||
throw new Exception("Invalid token");
|
||||
}
|
||||
// open connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = @"INSERT INTO Timelog(user,project,date,time) VALUES(@user,@project,@date,@time);";
|
||||
|
||||
var queryString = request.QueryString;
|
||||
string? user = queryString["user"];
|
||||
string? project = queryString["project"];
|
||||
string? time = queryString["time"];
|
||||
string? date = queryString["date"];
|
||||
// TODO validate somehow that the user who send the date is the
|
||||
// same user who has token, validate the project belongs to the
|
||||
// user
|
||||
int myInt;
|
||||
bool isValid = int.TryParse(time, out myInt);
|
||||
if (!string.IsNullOrEmpty(time) && isValid && myInt > 0) { }
|
||||
|
||||
if (!string.IsNullOrEmpty(date)) // use regex to validate{ }
|
||||
|
||||
if (string.IsNullOrEmpty(user)) // select * from User Where user=@user;
|
||||
{ }
|
||||
if (!string.IsNullOrEmpty(project))// select * from Project Where project=@project;
|
||||
{ }
|
||||
|
||||
cmd.Parameters.AddWithValue("@user", user);
|
||||
cmd.Parameters.AddWithValue("@project", project);
|
||||
cmd.Parameters.AddWithValue("@time", time);
|
||||
cmd.Parameters.AddWithValue("@date", date);
|
||||
// execute query and read results
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// close db connection
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
// there should be a better way to deal with data comming from sql
|
||||
public class Log
|
||||
{
|
||||
public object? f_name { get; set; }
|
||||
public object? l_name { get; set; }
|
||||
public object? mail { get; set; }
|
||||
public object? name { get; set; }
|
||||
public object? time { get; set; }
|
||||
public object? date { get; set; }
|
||||
public object? user { get; set; }
|
||||
}
|
||||
|
||||
public class Getall
|
||||
{
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// open connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
// get url params
|
||||
var queryString = request.QueryString;
|
||||
string? from = queryString["from"];
|
||||
string? to = queryString["to"];
|
||||
string? sortby = queryString["sortby"];
|
||||
string? offset = queryString["offset"];
|
||||
string? order = queryString["order"];
|
||||
order = order == "true" ? "ASC" : "DESC";
|
||||
// this shenanigan is needed to remove the "" around group by
|
||||
string sqlQ = @"SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user ";
|
||||
string offsetQ = " LIMIT 10 OFFSET " + offset + ";";
|
||||
// depending on the incoming parameters construct a Query
|
||||
if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from))
|
||||
{
|
||||
string whereQ = " WHERE t.date BETWEEN @from AND @to ";
|
||||
sqlQ = sqlQ + whereQ;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sortby))
|
||||
{
|
||||
string orderQ = " ORDER BY " + sortby + " " + order;
|
||||
sqlQ = sqlQ + orderQ;
|
||||
}
|
||||
// add the final line to the query
|
||||
cmd.CommandText = sqlQ + offsetQ;
|
||||
// those don't produce error if they don't find their variables
|
||||
cmd.Parameters.AddWithValue("@from", from);
|
||||
cmd.Parameters.AddWithValue("@to", to);
|
||||
|
||||
// execute query and read results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
List<Log> entries = new List<Log>();
|
||||
while (reader.Read())
|
||||
{
|
||||
entries.Add(new Log
|
||||
{
|
||||
f_name = reader["f_name"],
|
||||
l_name = reader["l_name"],
|
||||
user = reader["user"],
|
||||
date = reader["date"],
|
||||
name = reader["name"],
|
||||
time = reader["time"],
|
||||
mail = reader["mail"],
|
||||
});
|
||||
}
|
||||
// serialize JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(entries);
|
||||
// prepare response
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
response.ContentType = "application/json";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class TopTen
|
||||
{
|
||||
public object? user { get; set; }
|
||||
public object? date { get; set; }
|
||||
public object? project { get; set; }
|
||||
public object? f_name { get; set; }
|
||||
public object? l_name { get; set; }
|
||||
public object? name { get; set; }
|
||||
public object? total_time { get; set; }
|
||||
}
|
||||
public class Gettopten
|
||||
{
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// open db connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
var queryString = request.QueryString;
|
||||
string? from = queryString["from"];
|
||||
string? to = queryString["to"];
|
||||
string? filterBy = queryString["filterBy"];
|
||||
// this shenanigan is needed to remove the "" around
|
||||
// group by
|
||||
string req = @"SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user
|
||||
WHERE t.date BETWEEN @from AND @to
|
||||
GROUP BY " + filterBy + @" ORDER BY total_time DESC
|
||||
LIMIT 10;";
|
||||
cmd.CommandText = req;
|
||||
cmd.Parameters.AddWithValue("@from", from);
|
||||
cmd.Parameters.AddWithValue("@to", to);
|
||||
|
||||
// Execute the query and read the results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
List<TopTen> entries = new List<TopTen>();
|
||||
while (reader.Read())
|
||||
{
|
||||
entries.Add(new TopTen
|
||||
{
|
||||
user = reader["user"],
|
||||
date = reader["date"],
|
||||
project = reader["project"],
|
||||
f_name = reader["f_name"],
|
||||
l_name = reader["l_name"],
|
||||
name = reader["name"],
|
||||
total_time = reader["total_time"],
|
||||
});
|
||||
}
|
||||
// Serialize the data to JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(entries);
|
||||
// prepare response
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
response.ContentType = "application/json";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Getuser
|
||||
{
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// open connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = @"SELECT p.name, SUM(t.time)
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user
|
||||
WHERE User = @userid
|
||||
GROUP BY name;";
|
||||
var queryString = request.QueryString;
|
||||
string? userid = queryString["userid"];
|
||||
cmd.Parameters.AddWithValue("@userid", userid);
|
||||
// execute query and read results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
dynamic expando = new ExpandoObject();
|
||||
while (reader.Read())
|
||||
{
|
||||
((IDictionary<string?, object>)expando)[reader["name"].ToString()] = reader["SUM(t.time)"];
|
||||
|
||||
}
|
||||
// serialize JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(expando);
|
||||
// prepare response
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
response.ContentType = "application/json";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// close db connection
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+71
-42
@@ -1,13 +1,20 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
/* using System.Threading; */
|
||||
|
||||
|
||||
namespace Server
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void HandleMissingPath(HttpListenerResponse response)
|
||||
{
|
||||
response.StatusCode = 404;
|
||||
string errorMessage = "Not Found";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
static void Main()
|
||||
{
|
||||
// create server
|
||||
@@ -27,17 +34,10 @@ namespace Server
|
||||
Console.WriteLine("Server is listening on http://localhost:5000/");
|
||||
while (true)
|
||||
{
|
||||
// wait for request
|
||||
HttpListenerContext context = listener.GetContext();
|
||||
// get response and request
|
||||
HttpListenerRequest request = context.Request;
|
||||
HttpListenerResponse response = context.Response;
|
||||
// mysql connection
|
||||
string connectionString = "server=127.0.0.1;uid=monty;pwd=some_pass;database=timelog";
|
||||
MySqlConnection conn = new MySqlConnection(connectionString);
|
||||
|
||||
// url after localhost:5000/
|
||||
// i think the validation is unnecessry but the compiler doesn't
|
||||
string uri;
|
||||
if (request != null && request.Url != null)
|
||||
{
|
||||
@@ -47,44 +47,73 @@ namespace Server
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (uri)
|
||||
switch (request.HttpMethod)
|
||||
{
|
||||
case "/api/reset":
|
||||
Reset.run(conn, request, response);
|
||||
case "GET":
|
||||
switch (uri)
|
||||
{
|
||||
case "/api/reset":
|
||||
Reset.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/getall":
|
||||
/* Thread clientThread = new Thread(() => Getall.HandleRequest(request, response)); */
|
||||
/* clientThread.Start(); */
|
||||
Getall.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/gettopten":
|
||||
Gettopten.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/getuser":
|
||||
Getuser.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/createp":
|
||||
CreateProcedure.HandleRequest(request, response);
|
||||
break;
|
||||
default:
|
||||
HandleMissingPath(response);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "/api/getall":
|
||||
Getall.run(conn, request, response);
|
||||
break;
|
||||
case "/api/gettopten":
|
||||
Gettopten.run(conn, request, response);
|
||||
break;
|
||||
case "/api/getuser":
|
||||
Getuser.run(conn, request, response);
|
||||
break;
|
||||
case "/api/createp":
|
||||
CreateProcedure.run(conn, request, response);
|
||||
break;
|
||||
case "/api/register":
|
||||
Register.run(conn, request, response);
|
||||
break;
|
||||
case "/api/login":
|
||||
Console.WriteLine("111");
|
||||
Login.run(conn, request, response);
|
||||
break;
|
||||
case "/api/createlog":
|
||||
CreateLog.run(conn, request, response);
|
||||
case "POST":
|
||||
if (request.HasEntityBody)
|
||||
switch (uri)
|
||||
{
|
||||
case "/api/register":
|
||||
Register.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/login":
|
||||
Login.HandleRequest(request, response);
|
||||
break;
|
||||
case "/api/createlog":
|
||||
CreateLog.HandleRequest(request, response, context);
|
||||
break;
|
||||
default:
|
||||
HandleMissingPath(response);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleMissingPath(response);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
response.StatusCode = 404;
|
||||
string errorMessage = "Not Found";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
HandleMissingPath(response);
|
||||
break;
|
||||
}
|
||||
// send the response
|
||||
response.OutputStream.Close();
|
||||
|
||||
// try catch is neccessary because if you send a post with no
|
||||
// body the HTTPLIstener sends response automatically. Which
|
||||
// would crash the server since i try to send response but
|
||||
// respose has already been sent. It took me only 2 hours :)
|
||||
/* try */
|
||||
/* { */
|
||||
/* // send the response */
|
||||
/* response.OutputStream.Close(); */
|
||||
/* } */
|
||||
/* catch */
|
||||
/* { */
|
||||
/* Console.WriteLine("Tried sending post with no body"); */
|
||||
/* } */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Register
|
||||
{
|
||||
public static string HashPassword(string password)
|
||||
{
|
||||
// Generate a salt
|
||||
using (var rng = new RNGCryptoServiceProvider())
|
||||
{
|
||||
byte[] salt = new byte[16];
|
||||
rng.GetBytes(salt);
|
||||
|
||||
// Create a PBKDF2 instance to hash the password
|
||||
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256))
|
||||
{
|
||||
byte[] hash = pbkdf2.GetBytes(32);
|
||||
|
||||
// Combine the salt and the hash together
|
||||
byte[] hashBytes = new byte[48]; // 16 (salt) + 32 (hash)
|
||||
Array.Copy(salt, 0, hashBytes, 0, 16);
|
||||
Array.Copy(hash, 0, hashBytes, 16, 32);
|
||||
|
||||
// Return the final hash as a Base64 encoded string
|
||||
return Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: if one of the queries fails the others should be reverted in
|
||||
var queryString = request.QueryString;
|
||||
string? f_name = queryString["f_name"];
|
||||
string? l_name = queryString["l_name"];
|
||||
string? mail = queryString["mail"];
|
||||
string? password = queryString["password"];
|
||||
// validate parameters
|
||||
if (string.IsNullOrEmpty(f_name) || f_name.Length > 30 || f_name.Length < 2 ||
|
||||
string.IsNullOrEmpty(l_name) || l_name.Length > 30 || l_name.Length < 2 ||
|
||||
string.IsNullOrEmpty(mail) || mail.Length > 50 || mail.Length < 6 ||
|
||||
string.IsNullOrEmpty(password) || password.Length > 30 || password.Length < 10)
|
||||
{
|
||||
throw new Exception("Wrong parameters");
|
||||
}
|
||||
// open connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
// Insert into User
|
||||
cmd.CommandText = "INSERT INTO User(f_name,l_name,mail) VALUES(@f_name,@l_name,@mail)";
|
||||
cmd.Parameters.AddWithValue("@f_name", f_name);
|
||||
cmd.Parameters.AddWithValue("@l_name", l_name);
|
||||
cmd.Parameters.AddWithValue("@mail", mail);
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
// Get user ID
|
||||
cmd.CommandText = "SELECT id FROM User WHERE mail=@mail;";
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
reader.Read();
|
||||
var id = reader["id"];
|
||||
reader.Close();
|
||||
|
||||
// Insert into password
|
||||
cmd.CommandText = "INSERT INTO Password(user,password) VALUES(@id,@password)";
|
||||
cmd.Parameters.AddWithValue("@password", HashPassword(password));
|
||||
cmd.Parameters.AddWithValue("@id", id);
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// close db connection
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Reset
|
||||
{
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// open connection
|
||||
conn.Open();
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = "CALL InitDB";
|
||||
// execute query
|
||||
cmd.ExecuteNonQuery();
|
||||
// set up and send response
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
abstract public class Route
|
||||
{
|
||||
|
||||
public static string connectionString = "server=127.0.0.1;uid=monty;pwd=some_pass;database=timelog";
|
||||
public static void SendError(HttpListenerResponse response, Exception ex)
|
||||
{
|
||||
response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
response.Close();
|
||||
}
|
||||
public static void SendSuccess(HttpListenerResponse response)
|
||||
{
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
response.Close();
|
||||
}
|
||||
public static void SendSuccess(HttpListenerResponse response, string jsonResponse)
|
||||
{
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
response.ContentType = "application/json";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
response.Close();
|
||||
}
|
||||
/* public virtual void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response) { } */
|
||||
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("TimelogBackend")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+fd827866717246f0c1dc8296a83443554438188d")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+8e4317abde8c48644e2bc317481f0f846c577d4b")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("TimelogBackend")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("TimelogBackend")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -1 +1 @@
|
||||
390f35c991a10d59ca8975ac0af5ba18c35e466fb3f3b2889f5d0ac9b979b12e
|
||||
c543c95dc596bfc3bc702a1cdb58fc473192e89edf57457c326e82da9108ecd6
|
||||
|
||||
@@ -1 +1 @@
|
||||
21bef44b038939ad13b38cbd16140c4addb86bff3c9dfbda0b0851a88a920ccc
|
||||
97569e7a5b68ddf01d9512fdc58328cc85361fb7b0257ecbea320f5ee84a8cf6
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,112 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class CreateLog : Route
|
||||
{
|
||||
private static string secretKey = "stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";
|
||||
private static bool ValidateToken(string token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var validationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidIssuer = "TimeLogServer",
|
||||
ValidAudience = "TimeLogWebsite",
|
||||
IssuerSigningKey = key
|
||||
};
|
||||
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out SecurityToken validatedToken);
|
||||
return validatedToken != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response, HttpListenerContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
// check header
|
||||
var headers = request.Headers;
|
||||
string? token = headers["token"];
|
||||
if (!string.IsNullOrEmpty(token) && !ValidateToken(token))
|
||||
{
|
||||
throw new Exception("Invalid token");
|
||||
}
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
// extact data from body
|
||||
string body;
|
||||
using (StreamReader bodyReader = new StreamReader(request.InputStream, request.ContentEncoding))
|
||||
{
|
||||
body = bodyReader.ReadToEnd();
|
||||
}
|
||||
JObject jsonObject = JObject.Parse(body);
|
||||
string project = jsonObject["project"]?.ToString() ?? "";
|
||||
string time = jsonObject["time"]?.ToString() ?? "";
|
||||
string date = jsonObject["date"]?.ToString() ?? "";
|
||||
|
||||
// validate time
|
||||
if (!int.TryParse(time, out int myInt) || myInt < 0)
|
||||
throw new Exception("Incorect ammount of hours");
|
||||
//validate date
|
||||
Regex regex = new Regex(@"^\d{4}-\d{2}-\d{2}$");
|
||||
if (string.IsNullOrEmpty(date) || !regex.IsMatch(date))
|
||||
{
|
||||
throw new Exception("Incorrect date format");
|
||||
}
|
||||
// validate user
|
||||
// extract user from jwt
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var jwtToken = handler.ReadJwtToken(token);
|
||||
string? usernameClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == "user")?.Value ?? "";
|
||||
if (string.IsNullOrEmpty(usernameClaim))
|
||||
{
|
||||
throw new Exception("wrong user id");
|
||||
}
|
||||
|
||||
//validate project
|
||||
// TODO better project validation
|
||||
if (!string.IsNullOrEmpty(project))
|
||||
{
|
||||
throw new Exception("wrong project");
|
||||
}
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
|
||||
conn.Open();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = @"INSERT INTO Timelog(user,project,date,time)
|
||||
VALUES(@user,@project,@date,@time);";
|
||||
cmd.Parameters.AddWithValue("@user", usernameClaim);
|
||||
cmd.Parameters.AddWithValue("@project", project);
|
||||
cmd.Parameters.AddWithValue("@time", time);
|
||||
cmd.Parameters.AddWithValue("@date", date);
|
||||
// execute query and read results
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
SendSuccess(response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,19 @@ using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
namespace Server
|
||||
{
|
||||
public class CreateProcedure
|
||||
public class CreateProcedure : Route
|
||||
{
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = @"
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = @"
|
||||
CREATE PROCEDURE fill_timelog ()
|
||||
BEGIN
|
||||
DECLARE j INT DEFAULT 1;
|
||||
@@ -49,8 +52,8 @@ BEGIN
|
||||
SET users = users + 1;
|
||||
END WHILE;
|
||||
END;";
|
||||
cmd.ExecuteNonQuery();
|
||||
cmd.CommandText = @"CREATE PROCEDURE InitDB()
|
||||
cmd.ExecuteNonQuery();
|
||||
cmd.CommandText = @"CREATE PROCEDURE InitDB()
|
||||
BEGIN
|
||||
DECLARE i INT DEFAULT 1;
|
||||
TRUNCATE TABLE Timelog;
|
||||
@@ -111,23 +114,14 @@ BEGIN
|
||||
DROP TABLE temp_fname;
|
||||
DROP TABLE temp_lname;
|
||||
END;";
|
||||
cmd.ExecuteNonQuery();
|
||||
// prepare response
|
||||
response.StatusCode = (int)HttpStatusCode.OK;
|
||||
response.StatusDescription = "Status OK";
|
||||
cmd.ExecuteNonQuery();
|
||||
// prepare response
|
||||
SendSuccess(response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// close db connection
|
||||
conn.Close();
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
// there should be a better way to deal with data comming from sql
|
||||
public class Log
|
||||
{
|
||||
public object? f_name { get; set; }
|
||||
public object? l_name { get; set; }
|
||||
public object? mail { get; set; }
|
||||
public object? name { get; set; }
|
||||
public object? time { get; set; }
|
||||
public object? date { get; set; }
|
||||
public object? user { get; set; }
|
||||
}
|
||||
|
||||
public class Getall : Route
|
||||
{
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
// get url params
|
||||
var queryString = request.QueryString;
|
||||
string? from = queryString["from"];
|
||||
string? to = queryString["to"];
|
||||
string? sortby = queryString["sortby"];
|
||||
string? offset = queryString["offset"];
|
||||
string? order = queryString["order"];
|
||||
order = order == "true" ? "ASC" : "DESC";
|
||||
// this shenanigan is needed to remove the "" around group by
|
||||
string mainQuery = @"SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user ";
|
||||
string offsetQuery = " LIMIT 10 OFFSET " + offset + ";";
|
||||
// depending on the incoming parameters construct a Query
|
||||
if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from))
|
||||
{
|
||||
Regex regex = new Regex(@"^\d{4}-\d{2}-\d{2}$");
|
||||
if (!regex.IsMatch(to) || !regex.IsMatch(from))
|
||||
{
|
||||
throw new Exception("Incorrect date format");
|
||||
}
|
||||
string whereQuery = " WHERE t.date BETWEEN @from AND @to ";
|
||||
mainQuery = mainQuery + whereQuery;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sortby))
|
||||
{
|
||||
List<string> validSorting = new List<string> { "f_name", "l_name", "mail", "time", "date", "user", };
|
||||
if (!validSorting.Contains(sortby))
|
||||
{
|
||||
throw new Exception("Incorrect sorting value");
|
||||
}
|
||||
string orderQuery = " ORDER BY " + sortby + " " + order;
|
||||
mainQuery = mainQuery + orderQuery;
|
||||
}
|
||||
if (!int.TryParse(offset, out int myInt) || myInt < 0)
|
||||
throw new Exception("Incorect offset");
|
||||
// add the final line to the query
|
||||
cmd.CommandText = mainQuery + offsetQuery;
|
||||
// those don't produce error if they don't find their variables
|
||||
cmd.Parameters.AddWithValue("@from", from);
|
||||
cmd.Parameters.AddWithValue("@to", to);
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
cmd.Connection = conn;
|
||||
// execute query and read results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
List<Log> entries = new List<Log>();
|
||||
while (reader.Read())
|
||||
{
|
||||
entries.Add(new Log
|
||||
{
|
||||
f_name = reader["f_name"],
|
||||
l_name = reader["l_name"],
|
||||
user = reader["user"],
|
||||
date = reader["date"],
|
||||
name = reader["name"],
|
||||
time = reader["time"],
|
||||
mail = reader["mail"],
|
||||
});
|
||||
}
|
||||
// serialize JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(entries);
|
||||
SendSuccess(response, jsonResponse);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class TopTen
|
||||
{
|
||||
public object? user { get; set; }
|
||||
public object? date { get; set; }
|
||||
public object? project { get; set; }
|
||||
public object? f_name { get; set; }
|
||||
public object? l_name { get; set; }
|
||||
public object? name { get; set; }
|
||||
public object? total_time { get; set; }
|
||||
}
|
||||
public class Gettopten : Route
|
||||
{
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
var queryString = request.QueryString;
|
||||
string? from = queryString["from"];
|
||||
string? to = queryString["to"];
|
||||
string? filterBy = queryString["filterBy"];
|
||||
|
||||
if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from))
|
||||
{
|
||||
Regex regex = new Regex(@"^\d{4}-\d{2}-\d{2}$");
|
||||
if (!regex.IsMatch(to) || !regex.IsMatch(from))
|
||||
{
|
||||
throw new Exception("Incorrect date format");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Empty date format");
|
||||
}
|
||||
if (string.IsNullOrEmpty(filterBy))
|
||||
{
|
||||
throw new Exception("Empty filterby");
|
||||
}
|
||||
if (filterBy != "user" && filterBy != "project")
|
||||
{
|
||||
throw new Exception("Incorrect filterby");
|
||||
}
|
||||
|
||||
// this shenanigan is needed to remove the "" around
|
||||
// group by
|
||||
string req = @"SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user
|
||||
WHERE t.date BETWEEN @from AND @to
|
||||
GROUP BY " + filterBy + @" ORDER BY total_time DESC
|
||||
LIMIT 10;";
|
||||
cmd.CommandText = req;
|
||||
cmd.Parameters.AddWithValue("@from", from);
|
||||
cmd.Parameters.AddWithValue("@to", to);
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
cmd.Connection = conn;
|
||||
conn.Open();
|
||||
// Execute the query and read the results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
List<TopTen> entries = new List<TopTen>();
|
||||
while (reader.Read())
|
||||
{
|
||||
entries.Add(new TopTen
|
||||
{
|
||||
user = reader["user"],
|
||||
date = reader["date"],
|
||||
project = reader["project"],
|
||||
f_name = reader["f_name"],
|
||||
l_name = reader["l_name"],
|
||||
name = reader["name"],
|
||||
total_time = reader["total_time"],
|
||||
});
|
||||
}
|
||||
// Serialize the data to JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(entries);
|
||||
// prepare response
|
||||
SendSuccess(response, jsonResponse);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Dynamic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Getuser : Route
|
||||
{
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.CommandText = @"SELECT p.name, SUM(t.time)
|
||||
FROM Timelog t
|
||||
INNER JOIN Project p ON p.id=t.project
|
||||
INNER JOIN User u ON u.id=t.user
|
||||
WHERE User = @userid
|
||||
GROUP BY name;";
|
||||
var queryString = request.QueryString;
|
||||
string? userid = queryString["userid"];
|
||||
cmd.Parameters.AddWithValue("@userid", userid);
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
cmd.Connection = conn;
|
||||
// execute query and read results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
dynamic expando = new ExpandoObject();
|
||||
while (reader.Read())
|
||||
{
|
||||
((IDictionary<string?, object>)expando)[reader["name"].ToString()] = reader["SUM(t.time)"];
|
||||
|
||||
}
|
||||
// serialize JSON
|
||||
string jsonResponse = JsonConvert.SerializeObject(expando);
|
||||
// prepare response
|
||||
SendSuccess(response, jsonResponse);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
@@ -9,7 +10,7 @@ using System.Security.Cryptography;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Login
|
||||
public class Login : Route
|
||||
{
|
||||
private static string secretKey = "stronk-key-much-sercret-much-more-stronk-stronk-key-much-sercret-much-more-stronk";
|
||||
|
||||
@@ -23,7 +24,7 @@ namespace Server
|
||||
audience: "TimeLogWebsite",
|
||||
claims: new[]
|
||||
{
|
||||
new Claim(ClaimTypes.Name, user)
|
||||
new Claim("user", user)
|
||||
},
|
||||
expires: DateTime.Now.AddHours(2),
|
||||
signingCredentials: creds
|
||||
@@ -55,68 +56,64 @@ namespace Server
|
||||
}
|
||||
}
|
||||
|
||||
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
// 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.Connection = conn;
|
||||
cmd.CommandText = @"SELECT u.id,password FROM User u
|
||||
cmd.CommandText = @"SELECT u.id, password FROM User u
|
||||
INNER JOIN Password p ON p.user=u.id
|
||||
WHERE mail=@mail";
|
||||
var queryString = request.QueryString;
|
||||
string? mail = queryString["mail"];
|
||||
string? password = queryString["password"];
|
||||
WHERE mail=@mail;";
|
||||
cmd.Parameters.AddWithValue("@mail", mail);
|
||||
cmd.Parameters.AddWithValue("@password", password);
|
||||
// execute query and read results
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
string? userId = "";
|
||||
string? hashedPass = "";
|
||||
string? jsonResponse;
|
||||
while (reader.Read())
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
userId = Convert.ToString(reader["id"]);
|
||||
hashedPass = Convert.ToString(reader["password"]);
|
||||
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);
|
||||
}
|
||||
|
||||
// check username
|
||||
if (string.IsNullOrEmpty(userId) && string.IsNullOrEmpty(hashedPass))
|
||||
{
|
||||
throw new Exception("Error:Invalid Username or Password");
|
||||
}
|
||||
|
||||
//check password
|
||||
if (string.IsNullOrEmpty(password)
|
||||
|| string.IsNullOrEmpty(hashedPass)
|
||||
|| VerifyPassword(password, Convert.ToString(hashedPass)))
|
||||
{
|
||||
throw new Exception("Error:Invalid Username or Password");
|
||||
}
|
||||
|
||||
jsonResponse = JsonConvert.SerializeObject(GenerateToken(userId));
|
||||
|
||||
// prepare response
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
|
||||
response.ContentType = "application/json";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = $"Error: {ex.Message}";
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
|
||||
response.ContentType = "text/plain";
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// close db connection
|
||||
conn.Close();
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Security.Cryptography;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Register : Route
|
||||
{
|
||||
private static string HashPassword(string password)
|
||||
{
|
||||
// Generate a salt
|
||||
byte[] salt = new byte[16];
|
||||
RandomNumberGenerator.Fill(salt);
|
||||
// Create a PBKDF2 instance to hash the password
|
||||
using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA256))
|
||||
{
|
||||
byte[] hash = pbkdf2.GetBytes(32);
|
||||
|
||||
// Combine the salt and the hash together
|
||||
byte[] hashBytes = new byte[48]; // 16 (salt) + 32 (hash)
|
||||
Array.Copy(salt, 0, hashBytes, 0, 16);
|
||||
Array.Copy(hash, 0, hashBytes, 16, 32);
|
||||
|
||||
// Return the final hash as a Base64 encoded string
|
||||
return Convert.ToBase64String(hashBytes);
|
||||
}
|
||||
}
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
MySqlTransaction? transaction = null;
|
||||
try
|
||||
{
|
||||
// extract parameters from req body
|
||||
string body;
|
||||
using (StreamReader bodyReader = new StreamReader(request.InputStream, request.ContentEncoding))
|
||||
{
|
||||
body = bodyReader.ReadToEnd();
|
||||
}
|
||||
JObject jsonObject = JObject.Parse(body);
|
||||
string f_name = jsonObject["f_name"]?.ToString() ?? "";
|
||||
string l_name = jsonObject["l_name"]?.ToString() ?? "";
|
||||
string password = jsonObject["password"]?.ToString() ?? "";
|
||||
string mail = jsonObject["mail"]?.ToString() ?? "";
|
||||
|
||||
// validate parameters
|
||||
if (string.IsNullOrEmpty(f_name) || f_name.Length > 30 || f_name.Length < 2 ||
|
||||
string.IsNullOrEmpty(l_name) || l_name.Length > 30 || l_name.Length < 2 ||
|
||||
string.IsNullOrEmpty(mail) || mail.Length > 50 || mail.Length < 6 ||
|
||||
string.IsNullOrEmpty(password) || password.Length > 30 || password.Length < 10)
|
||||
{
|
||||
throw new Exception("Wrong parameters");
|
||||
}
|
||||
// open connection
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
|
||||
// Insert into User
|
||||
cmd.CommandText = "INSERT INTO User(f_name,l_name,mail) VALUES(@f_name,@l_name,@mail)";
|
||||
cmd.Parameters.AddWithValue("@f_name", f_name);
|
||||
cmd.Parameters.AddWithValue("@l_name", l_name);
|
||||
cmd.Parameters.AddWithValue("@mail", mail);
|
||||
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
conn.Open();
|
||||
transaction = conn.BeginTransaction();
|
||||
cmd.Connection = conn;
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
// Get user ID
|
||||
cmd.CommandText = "SELECT id FROM User WHERE mail=@mail;";
|
||||
MySqlDataReader reader = cmd.ExecuteReader();
|
||||
reader.Read();
|
||||
var id = reader["id"];
|
||||
reader.Close();
|
||||
|
||||
// Insert into password
|
||||
cmd.CommandText = "INSERT INTO Password(user,password) VALUES(@id,@password)";
|
||||
cmd.Parameters.AddWithValue("@password", HashPassword(password));
|
||||
cmd.Parameters.AddWithValue("@id", id);
|
||||
cmd.ExecuteNonQuery();
|
||||
transaction.Commit();
|
||||
|
||||
SendSuccess(response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (transaction != null)
|
||||
transaction.Rollback();
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using MySql.Data.MySqlClient;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Reset : Route
|
||||
{
|
||||
public static void HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
|
||||
{
|
||||
try
|
||||
{
|
||||
// prepare SQL query
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.CommandText = "CALL InitDB";
|
||||
using (MySqlConnection conn = new MySqlConnection(connectionString))
|
||||
{
|
||||
cmd.Connection = conn;
|
||||
// open connection
|
||||
conn.Open();
|
||||
// execute query
|
||||
cmd.ExecuteNonQuery();
|
||||
// set up and send response
|
||||
SendSuccess(response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SendError(response, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
url="localhost:5000/" # Replace with your URL
|
||||
|
||||
# Loop to send 1000 requests
|
||||
for i in {1..10000}
|
||||
do
|
||||
curl -s $url > /dev/null & # Send the request in the background
|
||||
done
|
||||
|
||||
# Wait for all background processes to finish
|
||||
wait
|
||||
echo "1000 requests sent!"
|
||||
Reference in New Issue
Block a user