Skip to content
Closed
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
40 changes: 31 additions & 9 deletions LinkRouter/App/Configuration/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ namespace LinkRouter.App.Configuration;

public class Config
{
[JsonProperty("RouteOn/")]
public string RootRoute { get; set; } = "https://example.com";
[JsonProperty("RouteOn/")] public string RootRoute { get; set; } = "https://example.com";

public NotFoundBehaviorConfig NotFoundBehavior { get; set; } = new();
public string AdminPassword { get; set; } = "admin";

public RedirectRoute[] Routes { get; set; } = [
public LinkTreeConfig LinkTree { get; set; } = new();

public RedirectRoute[] Routes { get; set; } =
[
new RedirectRoute()
{
Route = "/instagram",
Expand All @@ -22,10 +25,29 @@ public class Config
RedirectUrl = "https://example.com"
},
];

public class NotFoundBehaviorConfig
{
public bool RedirectOn404 { get; set; } = false;
public string RedirectUrl { get; set; } = "https://example.com/404";
}
}

public class LinkTreeConfig
{
public bool AddLinkTreePage { get; set; } = false;
public string LinkTreePageUrl { get; set; } = "/";

public LinkTreeHTML LinkTreeHTML { get; set; } = new();
}

public class LinkTreeHTML
{
public string Title { get; set; } = "";
public string CustomCSSUrl { get; set; } = "";
public string Author { get; set; } = "";
public string Description { get; set; } = "";
public string AuthorIconUrl { get; set; } = "";
public string FaviconUrl { get; set; } = "";
public string BackgroundColor { get; set; } = "#ffffff";
}

public class NotFoundBehaviorConfig
{
public bool RedirectOn404 { get; set; } = false;
public string RedirectUrl { get; set; } = "https://example.com/404";
}
68 changes: 42 additions & 26 deletions LinkRouter/App/Http/Controllers/RedirectController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LinkRouter.App.Configuration;
using LinkRouter.App.Configuration;
using LinkRouter.App.Models;
using Microsoft.AspNetCore.Mvc;
using Prometheus;

Expand All @@ -8,10 +9,9 @@ namespace LinkRouter.App.Http.Controllers;
[ApiController]
public class RedirectController : Controller
{

private readonly Config Config;


private readonly Counter RouteCounter = Metrics.CreateCounter(
"linkrouter_requests",
"Counts the number of requests to the link router",
Expand All @@ -20,8 +20,8 @@ public class RedirectController : Controller
LabelNames = new[] { "route" }
}
);


private readonly Counter NotFoundCounter = Metrics.CreateCounter(
"linkrouter_404_requests",
"Counts the number of not found requests to the link router",
Expand All @@ -39,36 +39,52 @@ public RedirectController(Config config)
[HttpGet("/{*path}")]
public IActionResult RedirectToExternalUrl(string path)
{
var redirectRoute = Config.Routes.FirstOrDefault(x => x.Route == path || x.Route == path + "/" || x.Route == "/" + path);
var normalizedPath = path.Trim('/');

var linkTreeUrl = Config.LinkTree.LinkTreePageUrl.Trim('/');
if (Config.LinkTree.AddLinkTreePage && normalizedPath == linkTreeUrl)
{
var html = Config.LinkTree.LinkTreeHTML;

return View(new LinkTreeViewModel
{
Title = html.Title,
CustomCSSUrl = string.IsNullOrWhiteSpace(html.CustomCSSUrl) || html.CustomCSSUrl.Length <= 1
? "css/linktree.css"
: html.CustomCSSUrl,
Author = html.Author,
Description = html.Description,
BackgroundColor = html.BackgroundColor,
AuthorIconUrl = html.AuthorIconUrl,
FaviconUrl = html.FaviconUrl,
Links = Config.Routes
});
}

var redirectRoute = Config.Routes.FirstOrDefault(x =>
string.Equals(x.Route.Trim('/'), normalizedPath, StringComparison.OrdinalIgnoreCase));

if (redirectRoute != null)
{
RouteCounter
.WithLabels(redirectRoute.Route)
.Inc();

RouteCounter.WithLabels(redirectRoute.Route).Inc();
return Redirect(redirectRoute.RedirectUrl);
}

NotFoundCounter
.WithLabels("/" + path)
.Inc();

if (Config.NotFoundBehavior.RedirectOn404)
return Redirect(Config.NotFoundBehavior.RedirectUrl);

return NotFound();

NotFoundCounter.WithLabels("/" + path).Inc();

return Redirect(Config.NotFoundBehavior.RedirectOn404 ? Config.NotFoundBehavior.RedirectUrl : path);
}



[HttpGet("/")]
public IActionResult GetRootRoute()
public IActionResult? GetRootRoute()
{
RouteCounter
.WithLabels("/")
.Inc();
string url = Config.RootRoute;
return Redirect(url);

var url = Config.RootRoute;

return Config.LinkTree is { LinkTreePageUrl: "/", AddLinkTreePage: true } ? null : Redirect(url);
}
}
63 changes: 63 additions & 0 deletions LinkRouter/App/Http/Pages/Admin/AdminLogin.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
@page "/_AdminLogin"
@using LinkRouter.App.Services
@inject IJSRuntime Js
@inject AdminService AdminService
@inject NavigationManager NavigationManager;

<title>Admin Login</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ndDqU0Gzau9qJ1lfW4pNLlhNTkCfHzAVBReH9diLvGRem5+R9g2FzA8ZGN954O5Q"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/lucide@latest"></script>
<script>
lucide.createIcons();
</script>
<style>* {
background-color: #212121;
}
</style>

<div class="d-flex justify-content-center mt-4 text-white">
<div class="text-white">
<h1>Password</h1>
<div>
<input
type="password"
id="passwordInput"
class="bg-secondary rounded-1"
@bind="PasswordInput"/>
</div>
<button @onclick="Login" class="btn btn-outline-light mt-3 d-flex justify-content-center">Login as
Admin
</button>
</div>
</div>

@code {
private string PasswordInput { get; set; } = "";

private async Task Login()
{
if (string.IsNullOrEmpty(PasswordInput))
{
await Js.InvokeVoidAsync("alert", "No Password input!");
return;
}

var isAdminPassword = await AdminService.IsValidAdminPassword(PasswordInput);

if (isAdminPassword)
{
await Js.InvokeVoidAsync("eval", $"document.cookie = 'password={PasswordInput};'");
await Js.InvokeVoidAsync("alert", "Logged in!");
NavigationManager.NavigateTo("/_Admin");
}
else
{
await Js.InvokeVoidAsync("alert", "Password mismatch!");
}
}

}
Loading
Loading