1
0
mirror of https://github.com/chylex/Discord-History-Tracker.git synced 2024-11-25 14:42:44 +01:00

Compare commits

..

3 Commits

10 changed files with 103 additions and 56 deletions

View File

@ -3,12 +3,9 @@ using System.Net;
using System.Text.Json; using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Service;
using DHT.Utils.Http; using DHT.Utils.Http;
using DHT.Utils.Logging; using DHT.Utils.Logging;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Primitives;
namespace DHT.Server.Endpoints; namespace DHT.Server.Endpoints;
@ -16,25 +13,14 @@ abstract class BaseEndpoint {
private static readonly Log Log = Log.ForType<BaseEndpoint>(); private static readonly Log Log = Log.ForType<BaseEndpoint>();
protected IDatabaseFile Db { get; } protected IDatabaseFile Db { get; }
protected ServerParameters Parameters { get; }
protected BaseEndpoint(IDatabaseFile db, ServerParameters parameters) { protected BaseEndpoint(IDatabaseFile db) {
this.Db = db; this.Db = db;
this.Parameters = parameters;
} }
private async Task Handle(HttpContext ctx, StringValues token) { public async Task Handle(HttpContext ctx) {
var request = ctx.Request;
var response = ctx.Response; var response = ctx.Response;
Log.Info("Request: " + request.GetDisplayUrl() + " (" + request.ContentLength + " B)");
if (token.Count != 1 || token[0] != Parameters.Token) {
Log.Error("Token: " + (token.Count == 1 ? token[0] : "<missing>"));
response.StatusCode = (int) HttpStatusCode.Forbidden;
return;
}
try { try {
response.StatusCode = (int) HttpStatusCode.OK; response.StatusCode = (int) HttpStatusCode.OK;
var output = await Respond(ctx); var output = await Respond(ctx);
@ -49,14 +35,6 @@ abstract class BaseEndpoint {
} }
} }
public async Task HandleGet(HttpContext ctx) {
await Handle(ctx, ctx.Request.Query["token"]);
}
public async Task HandlePost(HttpContext ctx) {
await Handle(ctx, ctx.Request.Headers["X-DHT-Token"]);
}
protected abstract Task<IHttpOutput> Respond(HttpContext ctx); protected abstract Task<IHttpOutput> Respond(HttpContext ctx);
protected static async Task<JsonElement> ReadJson(HttpContext ctx) { protected static async Task<JsonElement> ReadJson(HttpContext ctx) {

View File

@ -2,14 +2,13 @@ using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using DHT.Server.Data; using DHT.Server.Data;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Service;
using DHT.Utils.Http; using DHT.Utils.Http;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace DHT.Server.Endpoints; namespace DHT.Server.Endpoints;
sealed class GetAttachmentEndpoint : BaseEndpoint { sealed class GetAttachmentEndpoint : BaseEndpoint {
public GetAttachmentEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {} public GetAttachmentEndpoint(IDatabaseFile db) : base(db) {}
protected override Task<IHttpOutput> Respond(HttpContext ctx) { protected override Task<IHttpOutput> Respond(HttpContext ctx) {
string attachmentUrl = WebUtility.UrlDecode((string) ctx.Request.RouteValues["url"]!); string attachmentUrl = WebUtility.UrlDecode((string) ctx.Request.RouteValues["url"]!);

View File

@ -13,12 +13,16 @@ namespace DHT.Server.Endpoints;
sealed class GetTrackingScriptEndpoint : BaseEndpoint { sealed class GetTrackingScriptEndpoint : BaseEndpoint {
private static ResourceLoader Resources { get; } = new (Assembly.GetExecutingAssembly()); private static ResourceLoader Resources { get; } = new (Assembly.GetExecutingAssembly());
public GetTrackingScriptEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {} private readonly ServerParameters serverParameters;
public GetTrackingScriptEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db) {
serverParameters = parameters;
}
protected override async Task<IHttpOutput> Respond(HttpContext ctx) { protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
string bootstrap = await Resources.ReadTextAsync("Tracker/bootstrap.js"); string bootstrap = await Resources.ReadTextAsync("Tracker/bootstrap.js");
string script = bootstrap.Replace("= 0; /*[PORT]*/", "= " + Parameters.Port + ";") string script = bootstrap.Replace("= 0; /*[PORT]*/", "= " + serverParameters.Port + ";")
.Replace("/*[TOKEN]*/", HttpUtility.JavaScriptStringEncode(Parameters.Token)) .Replace("/*[TOKEN]*/", HttpUtility.JavaScriptStringEncode(serverParameters.Token))
.Replace("/*[IMPORTS]*/", await Resources.ReadJoinedAsync("Tracker/scripts/", '\n')) .Replace("/*[IMPORTS]*/", await Resources.ReadJoinedAsync("Tracker/scripts/", '\n'))
.Replace("/*[CSS-CONTROLLER]*/", await Resources.ReadTextAsync("Tracker/styles/controller.css")) .Replace("/*[CSS-CONTROLLER]*/", await Resources.ReadTextAsync("Tracker/styles/controller.css"))
.Replace("/*[CSS-SETTINGS]*/", await Resources.ReadTextAsync("Tracker/styles/settings.css")) .Replace("/*[CSS-SETTINGS]*/", await Resources.ReadTextAsync("Tracker/styles/settings.css"))

View File

@ -3,14 +3,13 @@ using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using DHT.Server.Data; using DHT.Server.Data;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Service;
using DHT.Utils.Http; using DHT.Utils.Http;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace DHT.Server.Endpoints; namespace DHT.Server.Endpoints;
sealed class TrackChannelEndpoint : BaseEndpoint { sealed class TrackChannelEndpoint : BaseEndpoint {
public TrackChannelEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {} public TrackChannelEndpoint(IDatabaseFile db) : base(db) {}
protected override async Task<IHttpOutput> Respond(HttpContext ctx) { protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
var root = await ReadJson(ctx); var root = await ReadJson(ctx);

View File

@ -9,7 +9,6 @@ using DHT.Server.Data;
using DHT.Server.Data.Filters; using DHT.Server.Data.Filters;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Download; using DHT.Server.Download;
using DHT.Server.Service;
using DHT.Utils.Collections; using DHT.Utils.Collections;
using DHT.Utils.Http; using DHT.Utils.Http;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -20,7 +19,7 @@ sealed class TrackMessagesEndpoint : BaseEndpoint {
private const string HasNewMessages = "1"; private const string HasNewMessages = "1";
private const string NoNewMessages = "0"; private const string NoNewMessages = "0";
public TrackMessagesEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {} public TrackMessagesEndpoint(IDatabaseFile db) : base(db) {}
protected override async Task<IHttpOutput> Respond(HttpContext ctx) { protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
var root = await ReadJson(ctx); var root = await ReadJson(ctx);

View File

@ -3,14 +3,13 @@ using System.Text.Json;
using System.Threading.Tasks; using System.Threading.Tasks;
using DHT.Server.Data; using DHT.Server.Data;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Service;
using DHT.Utils.Http; using DHT.Utils.Http;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace DHT.Server.Endpoints; namespace DHT.Server.Endpoints;
sealed class TrackUsersEndpoint : BaseEndpoint { sealed class TrackUsersEndpoint : BaseEndpoint {
public TrackUsersEndpoint(IDatabaseFile db, ServerParameters parameters) : base(db, parameters) {} public TrackUsersEndpoint(IDatabaseFile db) : base(db) {}
protected override async Task<IHttpOutput> Respond(HttpContext ctx) { protected override async Task<IHttpOutput> Respond(HttpContext ctx) {
var root = await ReadJson(ctx); var root = await ReadJson(ctx);

View File

@ -0,0 +1,44 @@
using System.Net;
using System.Threading.Tasks;
using DHT.Utils.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace DHT.Server.Service.Middlewares;
sealed class ServerAuthorizationMiddleware {
private static readonly Log Log = Log.ForType<ServerAuthorizationMiddleware>();
private readonly RequestDelegate next;
private readonly ServerParameters serverParameters;
public ServerAuthorizationMiddleware(RequestDelegate next, ServerParameters serverParameters) {
this.next = next;
this.serverParameters = serverParameters;
}
public async Task InvokeAsync(HttpContext context) {
var request = context.Request;
bool success = HttpMethods.IsGet(request.Method)
? CheckToken(request.Query["token"])
: CheckToken(request.Headers["X-DHT-Token"]);
if (success) {
await next(context);
}
else {
context.Response.StatusCode = (int) HttpStatusCode.Forbidden;
}
}
private bool CheckToken(StringValues token) {
if (token.Count == 1 && token[0] == serverParameters.Token) {
return true;
}
else {
Log.Error("Invalid token: " + (token.Count == 1 ? token[0] : "<missing>"));
return false;
}
}
}

View File

@ -0,0 +1,29 @@
using System.Diagnostics;
using System.Threading.Tasks;
using DHT.Utils.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
namespace DHT.Server.Service.Middlewares;
sealed class ServerLoggingMiddleware {
private static readonly Log Log = Log.ForType<ServerLoggingMiddleware>();
private readonly RequestDelegate next;
public ServerLoggingMiddleware(RequestDelegate next) {
this.next = next;
}
public async Task InvokeAsync(HttpContext context) {
var stopwatch = Stopwatch.StartNew();
await next(context);
stopwatch.Stop();
var request = context.Request;
var requestLength = request.ContentLength ?? 0L;
var responseStatus = context.Response.StatusCode;
var elapsedMs = stopwatch.ElapsedMilliseconds;
Log.Debug("Request to " + request.GetEncodedPathAndQuery() + " (" + requestLength + " B) returned " + responseStatus + ", took " + elapsedMs + " ms");
}
}

View File

@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis;
using System.Threading; using System.Threading;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Utils.Logging; using DHT.Utils.Logging;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -75,11 +74,11 @@ public static class ServerLauncher {
options.ListenLocalhost(port, static listenOptions => listenOptions.Protocols = HttpProtocols.Http1); options.ListenLocalhost(port, static listenOptions => listenOptions.Protocols = HttpProtocols.Http1);
} }
Server = WebHost.CreateDefaultBuilder() Server = new WebHostBuilder()
.ConfigureServices(AddServices) .ConfigureServices(AddServices)
.UseKestrel(SetKestrelOptions) .UseKestrel(SetKestrelOptions)
.UseStartup<Startup>() .UseStartup<Startup>()
.Build(); .Build();
Server.Start(); Server.Start();

View File

@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using DHT.Server.Database; using DHT.Server.Database;
using DHT.Server.Endpoints; using DHT.Server.Endpoints;
using DHT.Server.Service.Middlewares;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Http.Json;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -27,27 +28,23 @@ sealed class Startup {
builder.WithOrigins(AllowedOrigins).AllowCredentials().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("X-DHT"); builder.WithOrigins(AllowedOrigins).AllowCredentials().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("X-DHT");
}); });
}); });
services.AddRoutingCore();
} }
[SuppressMessage("ReSharper", "UnusedMember.Global")] [SuppressMessage("ReSharper", "UnusedMember.Global")]
public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifetime, IDatabaseFile db, ServerParameters parameters) { public void Configure(IApplicationBuilder app, IHostApplicationLifetime lifetime, IDatabaseFile db, ServerParameters parameters) {
app.UseRouting(); app.UseMiddleware<ServerLoggingMiddleware>();
app.UseCors(); app.UseCors();
app.UseMiddleware<ServerAuthorizationMiddleware>();
app.UseRouting();
app.UseEndpoints(endpoints => { app.UseEndpoints(endpoints => {
GetTrackingScriptEndpoint getTrackingScript = new (db, parameters); endpoints.MapGet("/get-tracking-script", new GetTrackingScriptEndpoint(db, parameters).Handle);
endpoints.MapGet("/get-tracking-script", context => getTrackingScript.HandleGet(context)); endpoints.MapGet("/get-attachment/{url}", new GetAttachmentEndpoint(db).Handle);
endpoints.MapPost("/track-channel", new TrackChannelEndpoint(db).Handle);
TrackChannelEndpoint trackChannel = new (db, parameters); endpoints.MapPost("/track-users", new TrackUsersEndpoint(db).Handle);
endpoints.MapPost("/track-channel", context => trackChannel.HandlePost(context)); endpoints.MapPost("/track-messages", new TrackMessagesEndpoint(db).Handle);
TrackUsersEndpoint trackUsers = new (db, parameters);
endpoints.MapPost("/track-users", context => trackUsers.HandlePost(context));
TrackMessagesEndpoint trackMessages = new (db, parameters);
endpoints.MapPost("/track-messages", context => trackMessages.HandlePost(context));
GetAttachmentEndpoint getAttachment = new (db, parameters);
endpoints.MapGet("/get-attachment/{url}", context => getAttachment.HandleGet(context));
}); });
} }
} }