Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions Controller/DeviceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public async Task<IActionResult> PostDeviceModel(DeviceModel deviceModel)
string result;
bool resultBool;

Console.WriteLine($"ClientToken: {deviceModel.ClientToken}");
Console.WriteLine($"DeviceToken: {deviceModel.DeviceToken}");
Console.WriteLine($"GotifyUrl: {deviceModel.GotifyUrl}");
AppLog.Info("Device", $"Register request client={AppLog.MaskSecret(deviceModel.ClientToken)} device={AppLog.MaskSecret(deviceModel.DeviceToken)} gotify={AppLog.SafeUrl(deviceModel.GotifyUrl)}");

if (
deviceModel.ClientToken.Length == 0 || deviceModel.ClientToken == "string" ||
Expand Down Expand Up @@ -66,7 +64,7 @@ public async Task<IActionResult> DeleteDevcice(string token)
string result;
bool resultBool;

Console.WriteLine($"Delete Token: {token}");
AppLog.Info("Device", $"Delete request client={AppLog.MaskSecret(token)}");
if (token.Length == 0 || token == "string")
{
result = "Error deleting device!";
Expand Down Expand Up @@ -145,9 +143,8 @@ public async Task<IActionResult> Test(string deviceToken)
var ntfy = new SecNtfy(Environments.secNtfyUrl);
if (deviceToken.Length > 0)
_ = await ntfy.SendNotification(deviceToken, "Test", "Test Notification");
if (Environments.isLogEnabled)
Console.WriteLine(ntfy.encTitle);
AppLog.Debug("Device", $"Test notification encryptedTitle={ntfy.encTitle}");

return Ok();
}
}
}
58 changes: 58 additions & 0 deletions Controller/UsersController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Reflection;
using iGotify_Notification_Assist.Models;
using iGotify_Notification_Assist.Services;
using Microsoft.AspNetCore.Mvc;

namespace iGotify_Notification_Assist.Controller;

[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
[HttpGet]
[ServiceFilter(typeof(AuthenticationFilter))]
public async Task<IActionResult> GetAllUsers()
{
List<Users> userList = await DatabaseService.GetUsers();
return Ok(new { Message = "Users successfully retrieved!", Data = userList });
}

[HttpPatch]
[ServiceFilter(typeof(AuthenticationFilter))]
public async Task<IActionResult> PatchUser([FromBody] Users? user)
{
if (user == null)
return Ok(new { Message = "User Body is empty!" });

bool isUpdated = await DatabaseService.UpdateUser(user);

if (isUpdated)
{
var gss = GotifySocketService.getInstance();
GotifySocketService.KillAllWsThread();
gss.Start();
}

return Ok(new { Message = isUpdated ? "User successfully updated!" : "User didn't updated!" });
}

[HttpDelete("{userId}")]
[ServiceFilter(typeof(AuthenticationFilter))]
public async Task<IActionResult> DeleteUser(int userId)
{
bool isDeleted = false;
List<Users> userList = await DatabaseService.GetUsers();
Users? usr = userList.Find(x => x.Uid == userId);
if (usr != null)
isDeleted = await usr.Delete();

if (isDeleted)
{
var gss = GotifySocketService.getInstance();
GotifySocketService.KillAllWsThread();
gss.Start();
}

return Ok(new { Message = isDeleted ? "User successfully deleted!" : "User didn't deleted!" });
}
}
31 changes: 24 additions & 7 deletions Models/DeviceModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,43 @@ public async Task<bool> Delete()
/// <param name="clientToken"></param>
public async Task SendNotifications(GotifyMessage iGotifyMessage, WebsocketClient webSock)
{
await SendNotifications(iGotifyMessage, webSock.Url.ToString(), webSock.Name ?? "");
}

/// <summary>
/// Send the passed notification from a native websocket context
/// </summary>
public async Task SendNotifications(GotifyMessage iGotifyMessage, string wsUrl, string clientToken)
{
if (string.IsNullOrWhiteSpace(clientToken))
{
AppLog.Warn("Notification", "Cannot send notification because client token is empty.");
return;
}

var title = iGotifyMessage.title;
var msg = iGotifyMessage.message;

var protocol = webSock.Url.ToString().Contains("ws://") ? "http://" : "https://";
var gotifyServerUrl = webSock.Url.ToString().Replace("ws://", "").Replace("wss://", "").Replace("\"", "")
var protocol = wsUrl.Contains("ws://") ? "http://" : "https://";
var gotifyServerUrl = wsUrl.Replace("ws://", "").Replace("wss://", "").Replace("\"", "")
.Split("/stream");
var imageUrl = gotifyServerUrl.Length > 0
? $"{protocol}{gotifyServerUrl[0]}$$${iGotifyMessage.appid}$$${webSock.Name}"
? $"{protocol}{gotifyServerUrl[0]}$$${iGotifyMessage.appid}$$${clientToken}"
: "";

var usr = await DatabaseService.GetUser(webSock.Name!);
var usr = await DatabaseService.GetUser(clientToken);

if (usr.Uid == 0)
{
Console.WriteLine("THERE'S SOMETHING WRONG HERE? NO USER FOUND");
AppLog.Warn("Notification", $"No user found for client={AppLog.MaskSecret(clientToken)}");
}

var ntfy = new SecNtfy(Environments.secNtfyUrl);
var response = await ntfy.SendNotification(usr.DeviceToken, title, msg, iGotifyMessage.priority == 10, imageUrl,
iGotifyMessage.priority);
Console.WriteLine(response != null ? JsonConvert.SerializeObject(response) : "Notification response is null");
AppLog.Debug("Notification",
response != null
? $"SecNtfy response client={AppLog.MaskSecret(clientToken)} response={JsonConvert.SerializeObject(response)}"
: $"SecNtfy response client={AppLog.MaskSecret(clientToken)} response=<null>");
}
}
}
5 changes: 5 additions & 0 deletions Models/Users.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public async Task<bool> Update()
{
return await DatabaseService.UpdateUser(this);
}

public async Task<bool> Delete()
{
return await DatabaseService.DeleteUser(ClientToken);
}
}
19 changes: 17 additions & 2 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,25 @@
options.SerializerOptions.PropertyNamingPolicy = null; // Preserve exact casing
});


if (Environments.enableUserUi)
{
builder.Services.AddSingleton<PasswordGenerator>();
builder.Services.AddScoped<AuthenticationFilter>();
}

builder.Services.AddSingleton(builder.Configuration);
builder.Services.AddOpenApi();
builder.Services.AddTransient<IStartupFilter, StartUpBuilder>();

var app = builder.Build();

if (Environments.enableUserUi)
{
app.UseDefaultFiles(); // sucht automatisch index.html
app.UseStaticFiles(); // aktiviert wwwroot
}

app.UsePathBase("/api");

app.UseCors(x => x
Expand All @@ -51,8 +65,9 @@
});
}

//app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

app.MapControllers();

if (Environments.enableUserUi)
app.MapFallbackToFile("index.html");

app.Run();
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Download Link to iGotify down below

*These three environment variables above aren't required when the Gotify & iGotify Instances available over a domain!*

* `ENABLE_CONSOLE_LOG` = you can disable unnecessary console logs (default: true)
* `ENABLE_CONSOLE_LOG` = enable application console logs (default: true)
* `ENABLE_SCALAR_UI` = you can now disable the Endpoint page (default: true)

*please write the boolean variables (true, false) in single quotes 'true'*
Expand Down
61 changes: 61 additions & 0 deletions Services/AppLog.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
namespace iGotify_Notification_Assist.Services;

internal static class AppLog
{
public static void Info(string area, string message)
{
Write("INFO", area, message);
}

public static void Warn(string area, string message)
{
Write("WARN", area, message);
}

public static void Error(string area, string message, Exception? exception = null)
{
Write("ERROR", area, exception == null ? message : $"{message} ({exception.GetType().Name}: {exception.Message})");
}

public static void Debug(string area, string message)
{
Write("DEBUG", area, message);
}

public static string MaskSecret(string? value)
{
if (string.IsNullOrWhiteSpace(value))
return "<empty>";

var trimmed = value.Trim();
if (trimmed.Length <= 8)
return "****";

return $"{trimmed[..4]}...{trimmed[^4..]}";
}

public static string SafeUrl(string? value)
{
if (string.IsNullOrWhiteSpace(value))
return "<empty>";

var normalized = value.Trim().Trim('"');
if (!normalized.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
!normalized.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
normalized = $"https://{normalized}";
}

return Uri.TryCreate(normalized, UriKind.Absolute, out var uri)
? uri.GetLeftPart(UriPartial.Authority)
: "<invalid-url>";
}

private static void Write(string level, string area, string message)
{
if (!Environments.isLogEnabled)
return;

Console.WriteLine($"[{level}] [{area}] {message}");
}
}
38 changes: 38 additions & 0 deletions Services/AuthenticationFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace iGotify_Notification_Assist.Services;

public class AuthenticationFilter : IAsyncActionFilter, IAsyncAuthorizationFilter
{
private string? token = "";

public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//Console.WriteLine(token);
await next();
}

public void OnActionExecuted(ActionExecutedContext context)
{
// our code after action executes
}

public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var auth = context.HttpContext.Request.Headers.Authorization;

if (auth.ToString().Length > 0 && auth.ToString().Contains("Bearer"))
{
var cleared = auth.ToString().Replace("Bearer ", "");
token = cleared;
var result = PasswordGenerator.IsValid(token);
if (!result)
context.Result = new UnauthorizedResult();
}
else
{
context.Result = new UnauthorizedResult();
}
}
}
33 changes: 20 additions & 13 deletions Services/DatabaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,23 +233,30 @@ public static async Task<Users> GetUser(string clientToken)
public static async Task<List<Users>> GetUsers()
{
var userList = new List<Users>();
var path = $"{GetLocationsOf.App}/data";
//Create Database File
var pathToDb = Path.Combine(path, "users.db");
var isDbFileExists = File.Exists(pathToDb);
try
{
var path = $"{GetLocationsOf.App}/data";
//Create Database File
var pathToDb = Path.Combine(path, "users.db");
var isDbFileExists = File.Exists(pathToDb);

if (!isDbFileExists) return userList;
await using var dbConnection = new SqliteConnection(GetConnectionString.UsersDb(pathToDb));
dbConnection.Open();
if (!isDbFileExists) return userList;
await using var dbConnection = new SqliteConnection(GetConnectionString.UsersDb(pathToDb));
dbConnection.Open();

// Create a sample table
const string selectAllQuery = "SELECT * FROM Users u;";
userList = (await dbConnection.QueryAsync<Users>(selectAllQuery)).ToList();
// Create a sample table
const string selectAllQuery = "SELECT * FROM Users u;";
userList = (await dbConnection.QueryAsync<Users>(selectAllQuery)).ToList();

// Perform other database operations as needed
// Perform other database operations as needed

// Close the connection when done
dbConnection.Close();
// Close the connection when done
dbConnection.Close();
}
catch (Exception e)
{
AppLog.Error("APP", e.Message);
}

return userList;
}
Expand Down
Loading
Loading